summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/angle/src/compiler/translator
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/angle/src/compiler/translator
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/angle/src/compiler/translator')
-rw-r--r--chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch177
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BaseTypes.h471
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp406
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h91
-rw-r--r--chromium/third_party/angle/src/compiler/translator/CodeGen.cpp38
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Common.h92
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Compiler.cpp579
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ConstantUnion.h282
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp185
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h78
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp139
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h52
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp63
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Diagnostics.h44
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp166
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h48
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h37
-rw-r--r--chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp77
-rw-r--r--chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h37
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp82
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h50
-rw-r--r--chromium/third_party/angle/src/compiler/translator/HashNames.h18
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InfoSink.cpp54
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InfoSink.h116
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Initialize.cpp760
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Initialize.h23
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp32
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeDll.h13
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h13
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp40
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h17
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp116
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeVariables.h50
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp263
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Intermediate.cpp1835
-rw-r--r--chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp211
-rw-r--r--chromium/third_party/angle/src/compiler/translator/LoopInfo.h80
-rw-r--r--chromium/third_party/angle/src/compiler/translator/MMap.h56
-rw-r--r--chromium/third_party/angle/src/compiler/translator/NodeSearch.h80
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp27
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputESSL.h26
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp57
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSL.h28
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp1080
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h91
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp4184
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputHLSL.h220
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ParseContext.cpp2649
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ParseContext.h169
-rw-r--r--chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp294
-rw-r--r--chromium/third_party/angle/src/compiler/translator/PoolAlloc.h300
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Pragma.h19
-rw-r--r--chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp58
-rw-r--r--chromium/third_party/angle/src/compiler/translator/QualifierAlive.h7
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp29
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemoveTree.h7
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RenameFunction.h36
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp132
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h37
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp38
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SearchSymbol.h33
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ShHandle.h180
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp445
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp241
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SymbolTable.h431
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp43
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h23
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp64
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h23
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp29
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h34
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Types.cpp250
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Types.h586
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp184
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h39
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp81
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h51
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp469
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h55
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp78
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h33
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp374
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariableInfo.h51
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp323
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariablePacker.h41
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp140
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VersionGLSL.h56
-rw-r--r--chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp37
-rw-r--r--chromium/third_party/angle/src/compiler/translator/compilerdebug.h53
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp97
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h212
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp227
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h181
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp65
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h30
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp69
-rw-r--r--chromium/third_party/angle/src/compiler/translator/generate_parser.sh28
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang.h16
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang.l558
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang.y1951
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp3360
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp5263
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_tab.h257
-rw-r--r--chromium/third_party/angle/src/compiler/translator/intermOut.cpp439
-rw-r--r--chromium/third_party/angle/src/compiler/translator/intermediate.h719
-rw-r--r--chromium/third_party/angle/src/compiler/translator/length_limits.h21
-rw-r--r--chromium/third_party/angle/src/compiler/translator/localintermediate.h55
-rw-r--r--chromium/third_party/angle/src/compiler/translator/osinclude.h66
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp64
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ossource_win.cpp57
-rw-r--r--chromium/third_party/angle/src/compiler/translator/parseConst.cpp251
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp136
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h38
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp17
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h31
-rw-r--r--chromium/third_party/angle/src/compiler/translator/util.cpp28
-rw-r--r--chromium/third_party/angle/src/compiler/translator/util.h20
117 files changed, 35162 insertions, 0 deletions
diff --git a/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch b/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch
new file mode 100644
index 00000000000..7af91f57653
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch
@@ -0,0 +1,177 @@
+--- a/src/compiler/glslang_lex.cpp
++++ b/src/compiler/glslang_lex.cpp
+@@ -68,6 +68,7 @@ typedef int16_t flex_int16_t;
+ typedef uint16_t flex_uint16_t;
+ typedef int32_t flex_int32_t;
+ typedef uint32_t flex_uint32_t;
++typedef uint64_t flex_uint64_t;
+ #else
+ typedef signed char flex_int8_t;
+ typedef short int flex_int16_t;
+@@ -191,6 +192,11 @@ typedef void* yyscan_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
+ #define EOB_ACT_CONTINUE_SCAN 0
+ #define EOB_ACT_END_OF_FILE 1
+ #define EOB_ACT_LAST_MATCH 2
+@@ -204,7 +210,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+- int yyl;\
++ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+@@ -226,11 +232,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+ #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -248,7 +249,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- int yy_n_chars;
++ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -327,7 +328,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+ void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+ void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+@@ -378,7 +379,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+ */
+ #define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+- yyleng = (size_t) (yy_cp - yy_bp); \
++ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+@@ -1035,8 +1036,8 @@ struct yyguts_t
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+- int yy_n_chars;
+- int yyleng_r;
++ yy_size_t yy_n_chars;
++ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+@@ -1089,7 +1090,7 @@ FILE *yyget_out (yyscan_t yyscanner );
+
+ void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+-int yyget_leng (yyscan_t yyscanner );
++yy_size_t yyget_leng (yyscan_t yyscanner );
+
+ char *yyget_text (yyscan_t yyscanner );
+
+@@ -1158,7 +1159,7 @@ static int input (yyscan_t yyscanner );
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+- int n; \
++ yy_size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+@@ -1317,7 +1318,7 @@ yy_find_action:
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+- int yyl;
++ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+@@ -2203,7 +2204,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ {
+- int num_to_read =
++ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+@@ -2217,7 +2218,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ if ( b->yy_is_our_buffer )
+ {
+- int new_size = b->yy_buf_size * 2;
++ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -2248,7 +2249,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- yyg->yy_n_chars, (size_t) num_to_read );
++ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+@@ -2373,7 +2374,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ { /* need more input */
+- int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
++ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+@@ -2660,7 +2661,7 @@ void yypop_buffer_state (yyscan_t yyscanner)
+ */
+ static void yyensure_buffer_stack (yyscan_t yyscanner)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+@@ -2758,12 +2759,11 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+- yy_size_t n;
+- int i;
++ yy_size_t n, i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2913,7 +2913,7 @@ FILE *yyget_out (yyscan_t yyscanner)
+ /** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+-int yyget_leng (yyscan_t yyscanner)
++yy_size_t yyget_leng (yyscan_t yyscanner)
+ {
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
diff --git a/chromium/third_party/angle/src/compiler/translator/BaseTypes.h b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h
new file mode 100644
index 00000000000..ba9ef5e609e
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h
@@ -0,0 +1,471 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+#include <assert.h>
+
+//
+// Precision qualifiers
+//
+enum TPrecision
+{
+ // These need to be kept sorted
+ EbpUndefined,
+ EbpLow,
+ EbpMedium,
+ EbpHigh
+};
+
+inline const char* getPrecisionString(TPrecision p)
+{
+ switch(p)
+ {
+ case EbpHigh: return "highp"; break;
+ case EbpMedium: return "mediump"; break;
+ case EbpLow: return "lowp"; break;
+ default: return "mediump"; break; // Safest fallback
+ }
+}
+
+//
+// Basic type. Arrays, vectors, etc., are orthogonal to this.
+//
+enum TBasicType
+{
+ EbtVoid,
+ EbtFloat,
+ EbtInt,
+ EbtUInt,
+ EbtBool,
+ EbtGVec4, // non type: represents vec4, ivec4 and uvec4
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D,
+ EbtSampler3D,
+ EbtSamplerCube,
+ EbtSampler2DArray,
+ EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
+ EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
+ EbtISampler2D,
+ EbtISampler3D,
+ EbtISamplerCube,
+ EbtISampler2DArray,
+ EbtUSampler2D,
+ EbtUSampler3D,
+ EbtUSamplerCube,
+ EbtUSampler2DArray,
+ EbtSampler2DShadow,
+ EbtSamplerCubeShadow,
+ EbtSampler2DArrayShadow,
+ EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
+ EbtGSampler2D, // non type: represents sampler2D, isampler2D and usampler2D
+ EbtGSampler3D, // non type: represents sampler3D, isampler3D and usampler3D
+ EbtGSamplerCube, // non type: represents samplerCube, isamplerCube and usamplerCube
+ EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray and usampler2DArray
+ EbtStruct,
+ EbtInterfaceBlock,
+ EbtAddress, // should be deprecated??
+ EbtInvariant // used as a type when qualifying a previously declared variable as being invariant
+};
+
+inline const char* getBasicString(TBasicType t)
+{
+ switch (t)
+ {
+ case EbtVoid: return "void"; break;
+ case EbtFloat: return "float"; break;
+ case EbtInt: return "int"; break;
+ case EbtUInt: return "uint"; break;
+ case EbtBool: return "bool"; break;
+ case EbtSampler2D: return "sampler2D"; break;
+ case EbtSampler3D: return "sampler3D"; break;
+ case EbtSamplerCube: return "samplerCube"; break;
+ case EbtSamplerExternalOES: return "samplerExternalOES"; break;
+ case EbtSampler2DRect: return "sampler2DRect"; break;
+ case EbtSampler2DArray: return "sampler2DArray"; break;
+ case EbtISampler2D: return "isampler2D"; break;
+ case EbtISampler3D: return "isampler3D"; break;
+ case EbtISamplerCube: return "isamplerCube"; break;
+ case EbtISampler2DArray: return "isampler2DArray"; break;
+ case EbtUSampler2D: return "usampler2D"; break;
+ case EbtUSampler3D: return "usampler3D"; break;
+ case EbtUSamplerCube: return "usamplerCube"; break;
+ case EbtUSampler2DArray: return "usampler2DArray"; break;
+ case EbtSampler2DShadow: return "sampler2DShadow"; break;
+ case EbtSamplerCubeShadow: return "samplerCubeShadow"; break;
+ case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; break;
+ case EbtStruct: return "structure"; break;
+ case EbtInterfaceBlock: return "interface block"; break;
+ default: return "unknown type";
+ }
+}
+
+inline bool IsSampler(TBasicType type)
+{
+ return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
+}
+
+inline bool IsIntegerSampler(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ return true;
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSampler2D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ return true;
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCube:
+ case EbtSamplerCubeShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSamplerCube(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCubeShadow:
+ return true;
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSampler3D(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ return true;
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ case EbtISampler2D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsSamplerArray(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DArrayShadow:
+ return true;
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DRect:
+ case EbtSamplerExternalOES:
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCube:
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool IsShadowSampler(TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2DShadow:
+ case EbtSamplerCubeShadow:
+ case EbtSampler2DArrayShadow:
+ return true;
+ case EbtISampler2D:
+ case EbtISampler3D:
+ case EbtISamplerCube:
+ case EbtISampler2DArray:
+ case EbtUSampler2D:
+ case EbtUSampler3D:
+ case EbtUSamplerCube:
+ case EbtUSampler2DArray:
+ case EbtSampler2D:
+ case EbtSampler3D:
+ case EbtSamplerCube:
+ case EbtSamplerExternalOES:
+ case EbtSampler2DRect:
+ case EbtSampler2DArray:
+ return false;
+ default:
+ assert(!IsSampler(type));
+ }
+
+ return false;
+}
+
+inline bool SupportsPrecision(TBasicType type)
+{
+ return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type);
+}
+
+//
+// Qualifiers and built-ins. These are mainly used to see what can be read
+// or written, and by the machine dependent translator to know which registers
+// to allocate variables in. Since built-ins tend to go to different registers
+// than varying or uniform, it makes sense they are peers, not sub-classes.
+//
+enum TQualifier
+{
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqInternal, // For internal use, not visible to the user
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqInvariantVaryingIn, // readonly, fragment shaders only
+ EvqInvariantVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+
+ EvqVertexIn, // Vertex shader input
+ EvqFragmentOut, // Fragment shader output
+ EvqVertexOut, // Vertex shader output
+ EvqFragmentIn, // Fragment shader input
+
+ // parameters
+ EvqIn,
+ EvqOut,
+ EvqInOut,
+ EvqConstReadOnly,
+
+ // built-ins written by vertex shader
+ EvqPosition,
+ EvqPointSize,
+
+ // built-ins read by fragment shader
+ EvqFragCoord,
+ EvqFrontFacing,
+ EvqPointCoord,
+
+ // built-ins written by fragment shader
+ EvqFragColor,
+ EvqFragData,
+ EvqFragDepth,
+
+ // GLSL ES 3.0 vertex output and fragment input
+ EvqSmooth, // Incomplete qualifier, smooth is the default
+ EvqFlat, // Incomplete qualifier
+ EvqSmoothOut = EvqSmooth,
+ EvqFlatOut = EvqFlat,
+ EvqCentroidOut, // Implies smooth
+ EvqSmoothIn,
+ EvqFlatIn,
+ EvqCentroidIn, // Implies smooth
+
+ // end of list
+ EvqLast
+};
+
+enum TLayoutMatrixPacking
+{
+ EmpUnspecified,
+ EmpRowMajor,
+ EmpColumnMajor
+};
+
+enum TLayoutBlockStorage
+{
+ EbsUnspecified,
+ EbsShared,
+ EbsPacked,
+ EbsStd140
+};
+
+struct TLayoutQualifier
+{
+ int location;
+ TLayoutMatrixPacking matrixPacking;
+ TLayoutBlockStorage blockStorage;
+
+ static TLayoutQualifier create()
+ {
+ TLayoutQualifier layoutQualifier;
+
+ layoutQualifier.location = -1;
+ layoutQualifier.matrixPacking = EmpUnspecified;
+ layoutQualifier.blockStorage = EbsUnspecified;
+
+ return layoutQualifier;
+ }
+
+ bool isEmpty() const
+ {
+ return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified;
+ }
+};
+
+//
+// This is just for debug print out, carried along with the definitions above.
+//
+inline const char* getQualifierString(TQualifier q)
+{
+ switch(q)
+ {
+ case EvqTemporary: return "Temporary"; break;
+ case EvqGlobal: return "Global"; break;
+ case EvqConst: return "const"; break;
+ case EvqConstReadOnly: return "const"; break;
+ case EvqAttribute: return "attribute"; break;
+ case EvqVaryingIn: return "varying"; break;
+ case EvqVaryingOut: return "varying"; break;
+ case EvqInvariantVaryingIn: return "invariant varying"; break;
+ case EvqInvariantVaryingOut:return "invariant varying"; break;
+ case EvqUniform: return "uniform"; break;
+ case EvqVertexIn: return "in"; break;
+ case EvqFragmentOut: return "out"; break;
+ case EvqVertexOut: return "out"; break;
+ case EvqFragmentIn: return "in"; break;
+ case EvqIn: return "in"; break;
+ case EvqOut: return "out"; break;
+ case EvqInOut: return "inout"; break;
+ case EvqPosition: return "Position"; break;
+ case EvqPointSize: return "PointSize"; break;
+ case EvqFragCoord: return "FragCoord"; break;
+ case EvqFrontFacing: return "FrontFacing"; break;
+ case EvqFragColor: return "FragColor"; break;
+ case EvqFragData: return "FragData"; break;
+ case EvqFragDepth: return "FragDepth"; break;
+ case EvqSmoothOut: return "smooth out"; break;
+ case EvqCentroidOut: return "centroid out"; break;
+ case EvqFlatOut: return "flat out"; break;
+ case EvqSmoothIn: return "smooth in"; break;
+ case EvqCentroidIn: return "centroid in"; break;
+ case EvqFlatIn: return "flat in"; break;
+ default: return "unknown qualifier";
+ }
+}
+
+inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq)
+{
+ switch (mpq)
+ {
+ case EmpUnspecified: return "mp_unspecified";
+ case EmpRowMajor: return "row_major";
+ case EmpColumnMajor: return "column_major";
+ default: return "unknown matrix packing";
+ }
+}
+
+inline const char* getBlockStorageString(TLayoutBlockStorage bsq)
+{
+ switch (bsq)
+ {
+ case EbsUnspecified: return "bs_unspecified";
+ case EbsShared: return "shared";
+ case EbsPacked: return "packed";
+ case EbsStd140: return "std140";
+ default: return "unknown block storage";
+ }
+}
+
+inline const char* getInterpolationString(TQualifier q)
+{
+ switch(q)
+ {
+ case EvqSmoothOut: return "smooth"; break;
+ case EvqCentroidOut: return "centroid"; break;
+ case EvqFlatOut: return "flat"; break;
+ case EvqSmoothIn: return "smooth"; break;
+ case EvqCentroidIn: return "centroid"; break;
+ case EvqFlatIn: return "flat"; break;
+ default: return "unknown interpolation";
+ }
+}
+
+#endif // _BASICTYPES_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp
new file mode 100644
index 00000000000..afbc16926ff
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,406 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+
+#include "compiler/translator/SymbolTable.h"
+
+namespace {
+
+// we use macros here instead of function definitions to work around more GLSL
+// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
+// problematic because if the argument has side-effects they will be repeatedly
+// evaluated. This is unlikely to show up in real shaders, but is something to
+// consider.
+const char* kFunctionEmulationVertexSource[] = {
+ "#error no emulation for cos(float)",
+ "#error no emulation for cos(vec2)",
+ "#error no emulation for cos(vec3)",
+ "#error no emulation for cos(vec4)",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const char* kFunctionEmulationFragmentSource[] = {
+ "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
+ "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
+ "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
+ "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const bool kFunctionEmulationVertexMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+const bool kFunctionEmulationFragmentMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ true, // TFunctionCos1
+ true, // TFunctionCos2
+ true, // TFunctionCos3
+ true, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+class BuiltInFunctionEmulationMarker : public TIntermTraverser {
+public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
+ : mEmulator(emulator)
+ {
+ }
+
+ virtual bool visitUnary(Visit visit, TIntermUnary* node)
+ {
+ if (visit == PreVisit) {
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), node->getOperand()->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ if (visit == PreVisit) {
+ // Here we handle all the built-in functions instead of the ones we
+ // currently identified as problematic.
+ switch (node->getOp()) {
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpMod:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpMul:
+ break;
+ default:
+ return true;
+ };
+ const TIntermSequence& sequence = node->getSequence();
+ // Right now we only handle built-in functions with two parameters.
+ if (sequence.size() != 2)
+ return true;
+ TIntermTyped* param1 = sequence[0]->getAsTyped();
+ TIntermTyped* param2 = sequence[1]->getAsTyped();
+ if (!param1 || !param2)
+ return true;
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), param1->getType(), param2->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+private:
+ BuiltInFunctionEmulator& mEmulator;
+};
+
+} // anonymous namepsace
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
+{
+ if (shaderType == SH_FRAGMENT_SHADER) {
+ mFunctionMask = kFunctionEmulationFragmentMask;
+ mFunctionSource = kFunctionEmulationFragmentSource;
+ } else {
+ mFunctionMask = kFunctionEmulationVertexMask;
+ mFunctionSource = kFunctionEmulationVertexSource;
+ }
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param1, param2);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ BuiltInFunctionEmulator::TBuiltInFunction function) {
+ if (function == TFunctionUnknown || mFunctionMask[function] == false)
+ return false;
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ if (mFunctions[i] == function)
+ return true;
+ }
+ mFunctions.push_back(function);
+ return true;
+}
+
+void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
+ TInfoSinkBase& out, bool withPrecision) const
+{
+ if (mFunctions.size() == 0)
+ return;
+ out << "// BEGIN: Generated code for built-in function emulation\n\n";
+ if (withPrecision) {
+ out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
+ << "#define webgl_emu_precision highp\n"
+ << "#else\n"
+ << "#define webgl_emu_precision mediump\n"
+ << "#endif\n\n";
+ } else {
+ out << "#define webgl_emu_precision\n\n";
+ }
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ out << mFunctionSource[mFunctions[i]] << "\n\n";
+ }
+ out << "// END: Generated code for built-in function emulation\n\n";
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param)
+{
+ if (param.getNominalSize() > 4 || param.getSecondarySize() > 4)
+ return TFunctionUnknown;
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpCos:
+ function = TFunctionCos1;
+ break;
+ case EOpLength:
+ function = TFunctionLength1;
+ break;
+ case EOpNormalize:
+ function = TFunctionNormalize1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param.isVector())
+ function += param.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ // Right now for all the emulated functions with two parameters, the two
+ // parameters have the same type.
+ if (param1.getNominalSize() != param2.getNominalSize() ||
+ param1.getSecondarySize() != param2.getSecondarySize() ||
+ param1.getNominalSize() > 4 || param1.getSecondarySize() > 4)
+ return TFunctionUnknown;
+
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpDistance:
+ function = TFunctionDistance1_1;
+ break;
+ case EOpDot:
+ function = TFunctionDot1_1;
+ break;
+ case EOpReflect:
+ function = TFunctionReflect1_1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param1.isVector())
+ function += param1.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
+ TIntermNode* root)
+{
+ ASSERT(root);
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::Cleanup()
+{
+ mFunctions.clear();
+}
+
+//static
+TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
+ const TString& name)
+{
+ ASSERT(name[name.length() - 1] == '(');
+ return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h
new file mode 100644
index 00000000000..9367b558ac0
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -0,0 +1,91 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/intermediate.h"
+
+//
+// This class decides which built-in functions need to be replaced with the
+// emulated ones.
+// It's only a workaround for OpenGL driver bugs, and isn't needed in general.
+//
+class BuiltInFunctionEmulator {
+public:
+ BuiltInFunctionEmulator(ShShaderType shaderType);
+ // Records that a function is called by the shader and might needs to be
+ // emulated. If the function's group is not in mFunctionGroupFilter, this
+ // becomes an no-op.
+ // Returns true if the function call needs to be replaced with an emulated
+ // one.
+ bool SetFunctionCalled(TOperator op, const TType& param);
+ bool SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2);
+
+ // Output function emulation definition. This should be before any other
+ // shader source.
+ void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const;
+
+ void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
+
+ void Cleanup();
+
+ // "name(" becomes "webgl_name_emu(".
+ static TString GetEmulatedFunctionName(const TString& name);
+
+private:
+ //
+ // Built-in functions.
+ //
+ enum TBuiltInFunction {
+ TFunctionCos1 = 0, // float cos(float);
+ TFunctionCos2, // vec2 cos(vec2);
+ TFunctionCos3, // vec3 cos(vec3);
+ TFunctionCos4, // vec4 cos(vec4);
+
+ TFunctionDistance1_1, // float distance(float, float);
+ TFunctionDistance2_2, // vec2 distance(vec2, vec2);
+ TFunctionDistance3_3, // vec3 distance(vec3, vec3);
+ TFunctionDistance4_4, // vec4 distance(vec4, vec4);
+
+ TFunctionDot1_1, // float dot(float, float);
+ TFunctionDot2_2, // vec2 dot(vec2, vec2);
+ TFunctionDot3_3, // vec3 dot(vec3, vec3);
+ TFunctionDot4_4, // vec4 dot(vec4, vec4);
+
+ TFunctionLength1, // float length(float);
+ TFunctionLength2, // float length(vec2);
+ TFunctionLength3, // float length(vec3);
+ TFunctionLength4, // float length(vec4);
+
+ TFunctionNormalize1, // float normalize(float);
+ TFunctionNormalize2, // vec2 normalize(vec2);
+ TFunctionNormalize3, // vec3 normalize(vec3);
+ TFunctionNormalize4, // vec4 normalize(vec4);
+
+ TFunctionReflect1_1, // float reflect(float, float);
+ TFunctionReflect2_2, // vec2 reflect(vec2, vec2);
+ TFunctionReflect3_3, // vec3 reflect(vec3, vec3);
+ TFunctionReflect4_4, // vec4 reflect(vec4, vec4);
+
+ TFunctionUnknown
+ };
+
+ TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
+ TBuiltInFunction IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2);
+
+ bool SetFunctionCalled(TBuiltInFunction function);
+
+ std::vector<TBuiltInFunction> mFunctions;
+
+ const bool* mFunctionMask; // a boolean flag for each function.
+ const char** mFunctionSource;
+};
+
+#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp b/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp
new file mode 100644
index 00000000000..c35dbdc77ff
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorESSL.h"
+#include "compiler/translator/TranslatorGLSL.h"
+#include "compiler/translator/TranslatorHLSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_ESSL_OUTPUT:
+ return new TranslatorESSL(type, spec);
+ case SH_GLSL_OUTPUT:
+ return new TranslatorGLSL(type, spec);
+ case SH_HLSL9_OUTPUT:
+ case SH_HLSL11_OUTPUT:
+ return new TranslatorHLSL(type, spec, output);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/Common.h b/chromium/third_party/angle/src/compiler/translator/Common.h
new file mode 100644
index 00000000000..1e4503e340c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Common.h
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <limits>
+#include <stdio.h>
+
+#include "compiler/translator/PoolAlloc.h"
+#include "compiler/translator/compilerdebug.h"
+#include "common/angleutils.h"
+
+struct TSourceLoc {
+ int first_file;
+ int first_line;
+ int last_file;
+ int last_line;
+};
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE() \
+ void* operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void* operator new(size_t, void *_Where) { return (_Where); } \
+ void operator delete(void*) { } \
+ void operator delete(void *, void *) { } \
+ void* operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void* operator new[](size_t, void *_Where) { return (_Where); } \
+ void operator delete[](void*) { } \
+ void operator delete[](void *, void *) { }
+
+//
+// Pool version of string.
+//
+typedef pool_allocator<char> TStringAllocator;
+typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
+inline TString* NewPoolTString(const char* s)
+{
+ void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TString));
+ return new(memory) TString(s);
+}
+
+//
+// Persistent string memory. Should only be used for strings that survive
+// across compiles.
+//
+#define TPersistString std::string
+#define TPersistStringStream std::ostringstream
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+ typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T> >() {}
+ TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
+ TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {}
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
+public:
+ typedef pool_allocator<std::pair<const K, D> > tAllocator;
+
+ TMap() : std::map<K, D, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {}
+};
+
+// Integer to TString conversion
+template <typename T>
+inline TString str(T i)
+{
+ ASSERT(std::numeric_limits<T>::is_integer);
+ char buffer[((8 * sizeof(T)) / 3) + 3];
+ const char *formatStr = std::numeric_limits<T>::is_signed ? "%d" : "%u";
+ snprintf(buffer, sizeof(buffer), formatStr, i);
+ return buffer;
+}
+
+#endif // _COMMON_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/Compiler.cpp b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp
new file mode 100644
index 00000000000..402715b8af1
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp
@@ -0,0 +1,579 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/DetectCallDepth.h"
+#include "compiler/translator/ForLoopUnroll.h"
+#include "compiler/translator/Initialize.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/RenameFunction.h"
+#include "compiler/translator/ShHandle.h"
+#include "compiler/translator/UnfoldShortCircuitAST.h"
+#include "compiler/translator/ValidateLimitations.h"
+#include "compiler/translator/ValidateOutputs.h"
+#include "compiler/translator/VariablePacker.h"
+#include "compiler/translator/depgraph/DependencyGraph.h"
+#include "compiler/translator/depgraph/DependencyGraphOutput.h"
+#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
+#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+bool IsWebGLBasedSpec(ShShaderSpec spec)
+{
+ return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
+}
+
+size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
+{
+ // WebGL defines a max token legnth of 256, while ES2 leaves max token
+ // size undefined. ES3 defines a max size of 1024 characters.
+ if (IsWebGLBasedSpec(spec))
+ {
+ return 256;
+ }
+ else
+ {
+ return 1024;
+ }
+}
+
+namespace {
+class TScopedPoolAllocator
+{
+ public:
+ TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
+ {
+ mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator()
+ {
+ SetGlobalPoolAllocator(NULL);
+ mAllocator->pop();
+ }
+
+ private:
+ TPoolAllocator* mAllocator;
+};
+
+class TScopedSymbolTableLevel
+{
+ public:
+ TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
+ {
+ ASSERT(mTable->atBuiltInLevel());
+ mTable->push();
+ }
+ ~TScopedSymbolTableLevel()
+ {
+ while (!mTable->atBuiltInLevel())
+ mTable->pop();
+ }
+
+ private:
+ TSymbolTable* mTable;
+};
+} // namespace
+
+TShHandleBase::TShHandleBase()
+{
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase()
+{
+ SetGlobalPoolAllocator(NULL);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+ : shaderType(type),
+ shaderSpec(spec),
+ outputType(output),
+ maxUniformVectors(0),
+ maxExpressionComplexity(0),
+ maxCallStackDepth(0),
+ fragmentPrecisionHigh(false),
+ clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
+ builtInFunctionEmulator(type)
+{
+}
+
+TCompiler::~TCompiler()
+{
+}
+
+bool TCompiler::Init(const ShBuiltInResources& resources)
+{
+ shaderVersion = 100;
+ maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
+ resources.MaxVertexUniformVectors :
+ resources.MaxFragmentUniformVectors;
+ maxExpressionComplexity = resources.MaxExpressionComplexity;
+ maxCallStackDepth = resources.MaxCallStackDepth;
+
+ SetGlobalPoolAllocator(&allocator);
+
+ // Generate built-in symbol table.
+ if (!InitBuiltInSymbolTable(resources))
+ return false;
+ InitExtensionBehavior(resources, extensionBehavior);
+ fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
+
+ arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
+ clampingStrategy = resources.ArrayIndexClampingStrategy;
+
+ hashFunction = resources.HashFunction;
+
+ return true;
+}
+
+bool TCompiler::compile(const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions)
+{
+ TScopedPoolAllocator scopedAlloc(&allocator);
+ clearResults();
+
+ if (numStrings == 0)
+ return true;
+
+ // If compiling for WebGL, validate loop and indexing as well.
+ if (IsWebGLBasedSpec(shaderSpec))
+ compileOptions |= SH_VALIDATE_LOOP_INDEXING;
+
+ // First string is path of source file if flag is set. The actual source follows.
+ const char* sourcePath = NULL;
+ size_t firstSource = 0;
+ if (compileOptions & SH_SOURCE_PATH)
+ {
+ sourcePath = shaderStrings[0];
+ ++firstSource;
+ }
+
+ TIntermediate intermediate(infoSink);
+ TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
+ shaderType, shaderSpec, compileOptions, true,
+ sourcePath, infoSink);
+ parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
+ SetGlobalParseContext(&parseContext);
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
+
+ // Parse shader.
+ bool success =
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
+ (parseContext.treeRoot != NULL);
+
+ shaderVersion = parseContext.getShaderVersion();
+
+ if (success)
+ {
+ TIntermNode* root = parseContext.treeRoot;
+ success = intermediate.postProcess(root);
+
+ // Disallow expressions deemed too complex.
+ if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
+ success = limitExpressionComplexity(root);
+
+ if (success)
+ success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
+
+ if (success && shaderVersion == 300 && shaderType == SH_FRAGMENT_SHADER)
+ success = validateOutputs(root);
+
+ if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
+ success = validateLimitations(root);
+
+ if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
+ success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
+
+ if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
+ rewriteCSSShader(root);
+
+ // Unroll for-loop markup needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
+ {
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
+ root->traverse(&marker);
+ }
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
+ {
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
+ root->traverse(&marker);
+ if (marker.samplerArrayIndexIsFloatLoopIndex())
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "sampler array index is float loop index";
+ success = false;
+ }
+ }
+
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
+ builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+
+ // Clamping uniform array bounds needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
+ arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+
+ if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
+ initializeGLPosition(root);
+
+ if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
+ {
+ UnfoldShortCircuitAST unfoldShortCircuit;
+ root->traverse(&unfoldShortCircuit);
+ unfoldShortCircuit.updateTree();
+ }
+
+ if (success && (compileOptions & SH_VARIABLES))
+ {
+ collectVariables(root);
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
+ {
+ success = enforcePackingRestrictions();
+ if (!success)
+ {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "too many uniforms";
+ }
+ }
+ if (success && shaderType == SH_VERTEX_SHADER &&
+ (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
+ initializeVaryingsWithoutStaticUse(root);
+ }
+
+ if (success && (compileOptions & SH_INTERMEDIATE_TREE))
+ intermediate.outputTree(root);
+
+ if (success && (compileOptions & SH_OBJECT_CODE))
+ translate(root);
+ }
+
+ // Cleanup memory.
+ intermediate.remove(parseContext.treeRoot);
+ SetGlobalParseContext(NULL);
+ return success;
+}
+
+bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
+{
+ compileResources = resources;
+ setResourceString();
+
+ assert(symbolTable.isEmpty());
+ symbolTable.push(); // COMMON_BUILTINS
+ symbolTable.push(); // ESSL1_BUILTINS
+ symbolTable.push(); // ESSL3_BUILTINS
+
+ TPublicType integer;
+ integer.type = EbtInt;
+ integer.primarySize = 1;
+ integer.secondarySize = 1;
+ integer.array = false;
+
+ TPublicType floatingPoint;
+ floatingPoint.type = EbtFloat;
+ floatingPoint.primarySize = 1;
+ floatingPoint.secondarySize = 1;
+ floatingPoint.array = false;
+
+ TPublicType sampler;
+ sampler.primarySize = 1;
+ sampler.secondarySize = 1;
+ sampler.array = false;
+
+ switch(shaderType)
+ {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpMedium);
+ break;
+ case SH_VERTEX_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpHigh);
+ symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
+ break;
+ default:
+ assert(false && "Language not supported");
+ }
+ // We set defaults for all the sampler types, even those that are
+ // only available if an extension exists.
+ for (int samplerType = EbtGuardSamplerBegin + 1;
+ samplerType < EbtGuardSamplerEnd; ++samplerType)
+ {
+ sampler.type = static_cast<TBasicType>(samplerType);
+ symbolTable.setDefaultPrecision(sampler, EbpLow);
+ }
+
+ InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
+
+ IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
+
+ return true;
+}
+
+void TCompiler::setResourceString()
+{
+ std::ostringstream strstream;
+ strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
+ << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
+ << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
+ << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
+ << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
+ << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
+ << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
+ << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
+ << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
+ << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
+ << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
+ << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
+ << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
+ << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
+ << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
+ << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
+ << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
+ << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
+ << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
+ << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
+ << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset;
+
+ builtInResourcesString = strstream.str();
+}
+
+void TCompiler::clearResults()
+{
+ arrayBoundsClamper.Cleanup();
+ infoSink.info.erase();
+ infoSink.obj.erase();
+ infoSink.debug.erase();
+
+ attribs.clear();
+ uniforms.clear();
+ varyings.clear();
+
+ builtInFunctionEmulator.Cleanup();
+
+ nameMap.clear();
+}
+
+bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
+{
+ DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
+ root->traverse(&detect);
+ switch (detect.detectCallDepth())
+ {
+ case DetectCallDepth::kErrorNone:
+ return true;
+ case DetectCallDepth::kErrorMissingMain:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Missing main()";
+ return false;
+ case DetectCallDepth::kErrorRecursion:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function recursion detected";
+ return false;
+ case DetectCallDepth::kErrorMaxDepthExceeded:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function call stack too deep";
+ return false;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+bool TCompiler::validateOutputs(TIntermNode* root)
+{
+ ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
+ root->traverse(&validateOutputs);
+ return (validateOutputs.numErrors() == 0);
+}
+
+void TCompiler::rewriteCSSShader(TIntermNode* root)
+{
+ RenameFunction renamer("main(", "css_main(");
+ root->traverse(&renamer);
+}
+
+bool TCompiler::validateLimitations(TIntermNode* root)
+{
+ ValidateLimitations validate(shaderType, infoSink.info);
+ root->traverse(&validate);
+ return validate.numErrors() == 0;
+}
+
+bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
+{
+ if (shaderSpec != SH_WEBGL_SPEC)
+ {
+ infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
+ return false;
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER)
+ {
+ TDependencyGraph graph(root);
+
+ // Output any errors first.
+ bool success = enforceFragmentShaderTimingRestrictions(graph);
+
+ // Then, output the dependency graph.
+ if (outputGraph)
+ {
+ TDependencyGraphOutput output(infoSink.info);
+ output.outputAllSpanningTrees(graph);
+ }
+
+ return success;
+ }
+ else
+ {
+ return enforceVertexShaderTimingRestrictions(root);
+ }
+}
+
+bool TCompiler::limitExpressionComplexity(TIntermNode* root)
+{
+ TMaxDepthTraverser traverser(maxExpressionComplexity+1);
+ root->traverse(&traverser);
+
+ if (traverser.getMaxDepth() > maxExpressionComplexity)
+ {
+ infoSink.info << "Expression too complex.";
+ return false;
+ }
+
+ TDependencyGraph graph(root);
+
+ for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+ iter != graph.endUserDefinedFunctionCalls();
+ ++iter)
+ {
+ TGraphFunctionCall* samplerSymbol = *iter;
+ TDependencyGraphTraverser graphTraverser;
+ samplerSymbol->traverse(&graphTraverser);
+ }
+
+ return true;
+}
+
+bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
+{
+ RestrictFragmentShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(graph);
+ return restrictor.numErrors() == 0;
+}
+
+bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
+{
+ RestrictVertexShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(root);
+ return restrictor.numErrors() == 0;
+}
+
+void TCompiler::collectVariables(TIntermNode* root)
+{
+ CollectVariables collect(attribs, uniforms, varyings, hashFunction);
+ root->traverse(&collect);
+}
+
+bool TCompiler::enforcePackingRestrictions()
+{
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
+}
+
+void TCompiler::initializeGLPosition(TIntermNode* root)
+{
+ InitializeVariables::InitVariableInfoList variables;
+ InitializeVariables::InitVariableInfo var(
+ "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
+ variables.push_back(var);
+ InitializeVariables initializer(variables);
+ root->traverse(&initializer);
+}
+
+void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
+{
+ InitializeVariables::InitVariableInfoList variables;
+ for (size_t ii = 0; ii < varyings.size(); ++ii)
+ {
+ const TVariableInfo& varying = varyings[ii];
+ if (varying.staticUse)
+ continue;
+ unsigned char primarySize = 1, secondarySize = 1;
+ switch (varying.type)
+ {
+ case SH_FLOAT:
+ break;
+ case SH_FLOAT_VEC2:
+ primarySize = 2;
+ break;
+ case SH_FLOAT_VEC3:
+ primarySize = 3;
+ break;
+ case SH_FLOAT_VEC4:
+ primarySize = 4;
+ break;
+ case SH_FLOAT_MAT2:
+ primarySize = 2;
+ secondarySize = 2;
+ break;
+ case SH_FLOAT_MAT3:
+ primarySize = 3;
+ secondarySize = 3;
+ break;
+ case SH_FLOAT_MAT4:
+ primarySize = 4;
+ secondarySize = 4;
+ break;
+ default:
+ ASSERT(false);
+ }
+ TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray);
+ TString name = varying.name.c_str();
+ if (varying.isArray)
+ {
+ type.setArraySize(varying.size);
+ name = name.substr(0, name.find_first_of('['));
+ }
+
+ InitializeVariables::InitVariableInfo var(name, type);
+ variables.push_back(var);
+ }
+ InitializeVariables initializer(variables);
+ root->traverse(&initializer);
+}
+
+const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+{
+ return extensionBehavior;
+}
+
+const ShBuiltInResources& TCompiler::getResources() const
+{
+ return compileResources;
+}
+
+const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
+{
+ return arrayBoundsClamper;
+}
+
+ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
+{
+ return clampingStrategy;
+}
+
+const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+{
+ return builtInFunctionEmulator;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h
new file mode 100644
index 00000000000..5fdba61546c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h
@@ -0,0 +1,282 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+#include <assert.h>
+
+class ConstantUnion {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ ConstantUnion()
+ {
+ iConst = 0;
+ type = EbtVoid;
+ }
+
+ void setIConst(int i) {iConst = i; type = EbtInt; }
+ void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
+ void setFConst(float f) {fConst = f; type = EbtFloat; }
+ void setBConst(bool b) {bConst = b; type = EbtBool; }
+
+ int getIConst() const { return iConst; }
+ unsigned int getUConst() const { return uConst; }
+ float getFConst() const { return fConst; }
+ bool getBConst() const { return bConst; }
+
+ bool operator==(const int i) const
+ {
+ return i == iConst;
+ }
+
+ bool operator==(const unsigned int u) const
+ {
+ return u == uConst;
+ }
+
+ bool operator==(const float f) const
+ {
+ return f == fConst;
+ }
+
+ bool operator==(const bool b) const
+ {
+ return b == bConst;
+ }
+
+ bool operator==(const ConstantUnion& constant) const
+ {
+ if (constant.type != type)
+ return false;
+
+ switch (type) {
+ case EbtInt:
+ return constant.iConst == iConst;
+ case EbtUInt:
+ return constant.uConst == uConst;
+ case EbtFloat:
+ return constant.fConst == fConst;
+ case EbtBool:
+ return constant.bConst == bConst;
+ default:
+ return false;
+ }
+ }
+
+ bool operator!=(const int i) const
+ {
+ return !operator==(i);
+ }
+
+ bool operator!=(const unsigned int u) const
+ {
+ return !operator==(u);
+ }
+
+ bool operator!=(const float f) const
+ {
+ return !operator==(f);
+ }
+
+ bool operator!=(const bool b) const
+ {
+ return !operator==(b);
+ }
+
+ bool operator!=(const ConstantUnion& constant) const
+ {
+ return !operator==(constant);
+ }
+
+ bool operator>(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst > constant.iConst;
+ case EbtUInt:
+ return uConst > constant.uConst;
+ case EbtFloat:
+ return fConst > constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ bool operator<(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst < constant.iConst;
+ case EbtUInt:
+ return uConst < constant.uConst;
+ case EbtFloat:
+ return fConst < constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ ConstantUnion operator+(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break;
+ case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator-(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break;
+ case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator*(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break;
+ case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator%(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator>>(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator<<(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator|(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator^(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
+ case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator||(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ TBasicType getType() const { return type; }
+private:
+
+ union {
+ int iConst; // used for ivec, scalar ints
+ unsigned int uConst; // used for uvec, scalar uints
+ bool bConst; // used for bvec, scalar bools
+ float fConst; // used for vec, mat, scalar floats
+ } ;
+
+ TBasicType type;
+};
+
+#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp
new file mode 100644
index 00000000000..bfc1d5852ff
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp
@@ -0,0 +1,185 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/DetectCallDepth.h"
+#include "compiler/translator/InfoSink.h"
+
+DetectCallDepth::FunctionNode::FunctionNode(const TString& fname)
+ : name(fname),
+ visit(PreVisit)
+{
+}
+
+const TString& DetectCallDepth::FunctionNode::getName() const
+{
+ return name;
+}
+
+void DetectCallDepth::FunctionNode::addCallee(
+ DetectCallDepth::FunctionNode* callee)
+{
+ for (size_t i = 0; i < callees.size(); ++i) {
+ if (callees[i] == callee)
+ return;
+ }
+ callees.push_back(callee);
+}
+
+int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth)
+{
+ ASSERT(visit == PreVisit);
+ ASSERT(detectCallDepth);
+
+ int maxDepth = depth;
+ visit = InVisit;
+ for (size_t i = 0; i < callees.size(); ++i) {
+ switch (callees[i]->visit) {
+ case InVisit:
+ // cycle detected, i.e., recursion detected.
+ return kInfiniteCallDepth;
+ case PostVisit:
+ break;
+ case PreVisit: {
+ // Check before we recurse so we don't go too depth
+ if (detectCallDepth->checkExceedsMaxDepth(depth))
+ return depth;
+ int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1);
+ // Check after we recurse so we can exit immediately and provide info.
+ if (detectCallDepth->checkExceedsMaxDepth(callDepth)) {
+ detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName();
+ return callDepth;
+ }
+ maxDepth = std::max(callDepth, maxDepth);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ visit = PostVisit;
+ return maxDepth;
+}
+
+void DetectCallDepth::FunctionNode::reset()
+{
+ visit = PreVisit;
+}
+
+DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth)
+ : TIntermTraverser(true, false, true, false),
+ currentFunction(NULL),
+ infoSink(infoSink),
+ maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth)
+{
+}
+
+DetectCallDepth::~DetectCallDepth()
+{
+ for (size_t i = 0; i < functions.size(); ++i)
+ delete functions[i];
+}
+
+bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ // Function declaration.
+ // Don't add FunctionNode here because node->getName() is the
+ // unmangled function name.
+ break;
+ case EOpFunction: {
+ // Function definition.
+ if (visit == PreVisit) {
+ currentFunction = findFunctionByName(node->getName());
+ if (currentFunction == NULL) {
+ currentFunction = new FunctionNode(node->getName());
+ functions.push_back(currentFunction);
+ }
+ } else if (visit == PostVisit) {
+ currentFunction = NULL;
+ }
+ break;
+ }
+ case EOpFunctionCall: {
+ // Function call.
+ if (visit == PreVisit) {
+ FunctionNode* func = findFunctionByName(node->getName());
+ if (func == NULL) {
+ func = new FunctionNode(node->getName());
+ functions.push_back(func);
+ }
+ if (currentFunction)
+ currentFunction->addCallee(func);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+bool DetectCallDepth::checkExceedsMaxDepth(int depth)
+{
+ return depth >= maxDepth;
+}
+
+void DetectCallDepth::resetFunctionNodes()
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ functions[i]->reset();
+ }
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func)
+{
+ currentFunction = NULL;
+ resetFunctionNodes();
+
+ int maxCallDepth = func->detectCallDepth(this, 1);
+
+ if (maxCallDepth == FunctionNode::kInfiniteCallDepth)
+ return kErrorRecursion;
+
+ if (maxCallDepth >= maxDepth)
+ return kErrorMaxDepthExceeded;
+
+ return kErrorNone;
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth()
+{
+ if (maxDepth != FunctionNode::kInfiniteCallDepth) {
+ // Check all functions because the driver may fail on them
+ // TODO: Before detectingRecursion, strip unused functions.
+ for (size_t i = 0; i < functions.size(); ++i) {
+ ErrorCode error = detectCallDepthForFunction(functions[i]);
+ if (error != kErrorNone)
+ return error;
+ }
+ } else {
+ FunctionNode* main = findFunctionByName("main(");
+ if (main == NULL)
+ return kErrorMissingMain;
+
+ return detectCallDepthForFunction(main);
+ }
+
+ return kErrorNone;
+}
+
+DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName(
+ const TString& name)
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ if (functions[i]->getName() == name)
+ return functions[i];
+ }
+ return NULL;
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h
new file mode 100644
index 00000000000..cb76f1de02a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DETECT_RECURSION_H_
+#define COMPILER_DETECT_RECURSION_H_
+
+#include <limits.h>
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/VariableInfo.h"
+
+class TInfoSink;
+
+// Traverses intermediate tree to detect function recursion.
+class DetectCallDepth : public TIntermTraverser {
+public:
+ enum ErrorCode {
+ kErrorMissingMain,
+ kErrorRecursion,
+ kErrorMaxDepthExceeded,
+ kErrorNone
+ };
+
+ DetectCallDepth(TInfoSink& infoSync, bool limitCallStackDepth, int maxCallStackDepth);
+ ~DetectCallDepth();
+
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+
+ bool checkExceedsMaxDepth(int depth);
+
+ ErrorCode detectCallDepth();
+
+private:
+ class FunctionNode {
+ public:
+ static const int kInfiniteCallDepth = INT_MAX;
+
+ FunctionNode(const TString& fname);
+
+ const TString& getName() const;
+
+ // If a function is already in the callee list, this becomes a no-op.
+ void addCallee(FunctionNode* callee);
+
+ // Returns kInifinityCallDepth if recursive function calls are detected.
+ int detectCallDepth(DetectCallDepth* detectCallDepth, int depth);
+
+ // Reset state.
+ void reset();
+
+ private:
+ // mangled function name is unique.
+ TString name;
+
+ // functions that are directly called by this function.
+ TVector<FunctionNode*> callees;
+
+ Visit visit;
+ };
+
+ ErrorCode detectCallDepthForFunction(FunctionNode* func);
+ FunctionNode* findFunctionByName(const TString& name);
+ void resetFunctionNodes();
+
+ TInfoSink& getInfoSink() { return infoSink; }
+
+ TVector<FunctionNode*> functions;
+ FunctionNode* currentFunction;
+ TInfoSink& infoSink;
+ int maxDepth;
+
+ DetectCallDepth(const DetectCallDepth&);
+ void operator=(const DetectCallDepth&);
+};
+
+#endif // COMPILER_DETECT_RECURSION_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp
new file mode 100644
index 00000000000..334eb0bfa8b
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp
@@ -0,0 +1,139 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#include "compiler/translator/DetectDiscontinuity.h"
+
+#include "compiler/translator/ParseContext.h"
+
+namespace sh
+{
+bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
+{
+ mLoopDepth = 0;
+ mLoopDiscontinuity = false;
+ node->traverse(this);
+ return mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
+{
+ if (visit == PreVisit)
+ {
+ ++mLoopDepth;
+ }
+ else if (visit == PostVisit)
+ {
+ --mLoopDepth;
+ }
+
+ return true;
+}
+
+bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mLoopDiscontinuity)
+ {
+ return false;
+ }
+
+ if (!mLoopDepth)
+ {
+ return true;
+ }
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ break;
+ case EOpBreak:
+ case EOpContinue:
+ case EOpReturn:
+ mLoopDiscontinuity = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ return !mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ return !mLoopDiscontinuity;
+}
+
+bool containsLoopDiscontinuity(TIntermNode *node)
+{
+ DetectLoopDiscontinuity detectLoopDiscontinuity;
+ return detectLoopDiscontinuity.traverse(node);
+}
+
+bool DetectGradientOperation::traverse(TIntermNode *node)
+{
+ mGradientOperation = false;
+ node->traverse(this);
+ return mGradientOperation;
+}
+
+bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpDFdx:
+ case EOpDFdy:
+ mGradientOperation = true;
+ default:
+ break;
+ }
+
+ return !mGradientOperation;
+}
+
+bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ if (node->getOp() == EOpFunctionCall)
+ {
+ if (!node->isUserDefined())
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (name == "texture2D" ||
+ name == "texture2DProj" ||
+ name == "textureCube")
+ {
+ mGradientOperation = true;
+ }
+ }
+ else
+ {
+ // When a user defined function is called, we have to
+ // conservatively assume it to contain gradient operations
+ mGradientOperation = true;
+ }
+ }
+
+ return !mGradientOperation;
+}
+
+bool containsGradientOperation(TIntermNode *node)
+{
+ DetectGradientOperation detectGradientOperation;
+ return detectGradientOperation.traverse(node);
+}
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h
new file mode 100644
index 00000000000..1dd8be92335
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#ifndef COMPILER_DETECTDISCONTINUITY_H_
+#define COMPILER_DETECTDISCONTINUITY_H_
+
+#include "compiler/translator/intermediate.h"
+
+namespace sh
+{
+// Checks whether a loop can run for a variable number of iterations
+class DetectLoopDiscontinuity : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitBranch(Visit visit, TIntermBranch *node);
+ bool visitLoop(Visit visit, TIntermLoop *loop);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ int mLoopDepth;
+ bool mLoopDiscontinuity;
+};
+
+bool containsLoopDiscontinuity(TIntermNode *node);
+
+// Checks for intrinsic functions which compute gradients
+class DetectGradientOperation : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitUnary(Visit visit, TIntermUnary *node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ bool mGradientOperation;
+};
+
+bool containsGradientOperation(TIntermNode *node);
+
+}
+
+#endif // COMPILER_DETECTDISCONTINUITY_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp
new file mode 100644
index 00000000000..92db3e55cfb
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/Diagnostics.h"
+
+#include "compiler/translator/compilerdebug.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/preprocessor/SourceLocation.h"
+
+TDiagnostics::TDiagnostics(TInfoSink& infoSink) :
+ mInfoSink(infoSink),
+ mNumErrors(0),
+ mNumWarnings(0)
+{
+}
+
+TDiagnostics::~TDiagnostics()
+{
+}
+
+void TDiagnostics::writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra)
+{
+ TPrefixType prefix = EPrefixNone;
+ switch (severity)
+ {
+ case PP_ERROR:
+ ++mNumErrors;
+ prefix = EPrefixError;
+ break;
+ case PP_WARNING:
+ ++mNumWarnings;
+ prefix = EPrefixWarning;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ TInfoSinkBase& sink = mInfoSink.info;
+ /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
+ sink.prefix(prefix);
+ sink.location(loc.file, loc.line);
+ sink << "'" << token << "' : " << reason << " " << extra << "\n";
+}
+
+void TDiagnostics::writeDebug(const std::string& str)
+{
+ mInfoSink.debug << str;
+}
+
+void TDiagnostics::print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text)
+{
+ writeInfo(severity(id), loc, message(id), text, "");
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.h b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h
new file mode 100644
index 00000000000..664da7803b8
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIAGNOSTICS_H_
+#define COMPILER_DIAGNOSTICS_H_
+
+#include "compiler/preprocessor/DiagnosticsBase.h"
+
+class TInfoSink;
+
+class TDiagnostics : public pp::Diagnostics
+{
+ public:
+ TDiagnostics(TInfoSink& infoSink);
+ virtual ~TDiagnostics();
+
+ TInfoSink& infoSink() { return mInfoSink; }
+
+ int numErrors() const { return mNumErrors; }
+ int numWarnings() const { return mNumWarnings; }
+
+ void writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra);
+
+ void writeDebug(const std::string& str);
+
+ protected:
+ virtual void print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text);
+
+ private:
+ TInfoSink& mInfoSink;
+ int mNumErrors;
+ int mNumWarnings;
+};
+
+#endif // COMPILER_DIAGNOSTICS_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp
new file mode 100644
index 00000000000..59d2835f7b7
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp
@@ -0,0 +1,166 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/DirectiveHandler.h"
+
+#include <sstream>
+
+#include "compiler/translator/compilerdebug.h"
+#include "compiler/translator/Diagnostics.h"
+
+static TBehavior getBehavior(const std::string& str)
+{
+ static const std::string kRequire("require");
+ static const std::string kEnable("enable");
+ static const std::string kDisable("disable");
+ static const std::string kWarn("warn");
+
+ if (str == kRequire) return EBhRequire;
+ else if (str == kEnable) return EBhEnable;
+ else if (str == kDisable) return EBhDisable;
+ else if (str == kWarn) return EBhWarn;
+ return EBhUndefined;
+}
+
+TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics,
+ int& shaderVersion)
+ : mExtensionBehavior(extBehavior),
+ mDiagnostics(diagnostics),
+ mShaderVersion(shaderVersion)
+{
+}
+
+TDirectiveHandler::~TDirectiveHandler()
+{
+}
+
+void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
+ const std::string& msg)
+{
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", "");
+}
+
+void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value)
+{
+ static const std::string kSTDGL("STDGL");
+ static const std::string kOptimize("optimize");
+ static const std::string kDebug("debug");
+ static const std::string kOn("on");
+ static const std::string kOff("off");
+
+ bool invalidValue = false;
+ if (name == kSTDGL)
+ {
+ // The STDGL pragma is used to reserve pragmas for use by future
+ // revisions of GLSL. Ignore it.
+ return;
+ }
+ else if (name == kOptimize)
+ {
+ if (value == kOn) mPragma.optimize = true;
+ else if (value == kOff) mPragma.optimize = false;
+ else invalidValue = true;
+ }
+ else if (name == kDebug)
+ {
+ if (value == kOn) mPragma.debug = true;
+ else if (value == kOff) mPragma.debug = false;
+ else invalidValue = true;
+ }
+ else
+ {
+ mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
+ return;
+ }
+
+ if (invalidValue)
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "invalid pragma value", value,
+ "'on' or 'off' expected");
+}
+
+void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior)
+{
+ static const std::string kExtAll("all");
+
+ TBehavior behaviorVal = getBehavior(behavior);
+ if (behaviorVal == EBhUndefined)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "behavior", name, "invalid");
+ return;
+ }
+
+ if (name == kExtAll)
+ {
+ if (behaviorVal == EBhRequire)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "extension", name,
+ "cannot have 'require' behavior");
+ }
+ else if (behaviorVal == EBhEnable)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "extension", name,
+ "cannot have 'enable' behavior");
+ }
+ else
+ {
+ for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
+ iter != mExtensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ return;
+ }
+
+ TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
+ if (iter != mExtensionBehavior.end())
+ {
+ iter->second = behaviorVal;
+ return;
+ }
+
+ pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR;
+ switch (behaviorVal) {
+ case EBhRequire:
+ severity = pp::Diagnostics::PP_ERROR;
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ severity = pp::Diagnostics::PP_WARNING;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ mDiagnostics.writeInfo(severity, loc,
+ "extension", name, "is not supported");
+}
+
+void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
+ int version)
+{
+ if (version == 100 ||
+ version == 300)
+ {
+ mShaderVersion = version;
+ }
+ else
+ {
+ std::stringstream stream;
+ stream << version;
+ std::string str = stream.str();
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
+ "version number", str, "not supported");
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h
new file mode 100644
index 00000000000..69418c277af
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIRECTIVE_HANDLER_H_
+#define COMPILER_DIRECTIVE_HANDLER_H_
+
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/Pragma.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+
+class TDiagnostics;
+
+class TDirectiveHandler : public pp::DirectiveHandler
+{
+ public:
+ TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics,
+ int& shaderVersion);
+ virtual ~TDirectiveHandler();
+
+ const TPragma& pragma() const { return mPragma; }
+ const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; }
+
+ virtual void handleError(const pp::SourceLocation& loc,
+ const std::string& msg);
+
+ virtual void handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value);
+
+ virtual void handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior);
+
+ virtual void handleVersion(const pp::SourceLocation& loc,
+ int version);
+
+ private:
+ TPragma mPragma;
+ TExtensionBehavior& mExtensionBehavior;
+ TDiagnostics& mDiagnostics;
+ int& mShaderVersion;
+};
+
+#endif // COMPILER_DIRECTIVE_HANDLER_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h b/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h
new file mode 100644
index 00000000000..5c1595fb212
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
+#define _EXTENSION_BEHAVIOR_INCLUDED_
+
+#include <map>
+#include <string>
+
+typedef enum
+{
+ EBhRequire,
+ EBhEnable,
+ EBhWarn,
+ EBhDisable,
+ EBhUndefined
+} TBehavior;
+
+inline const char* getBehaviorString(TBehavior b)
+{
+ switch(b)
+ {
+ case EBhRequire: return "require";
+ case EBhEnable: return "enable";
+ case EBhWarn: return "warn";
+ case EBhDisable: return "disable";
+ default: return NULL;
+ }
+}
+
+// Mapping between extension name and behavior.
+typedef std::map<std::string, TBehavior> TExtensionBehavior;
+
+#endif // _EXTENSION_TABLE_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp
new file mode 100644
index 00000000000..a751b768b78
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/FlagStd140Structs.h"
+
+namespace sh
+{
+
+bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getRight()->getBasicType() == EbtStruct)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexDirectStruct:
+ if (isInStd140InterfaceBlock(binaryNode->getLeft()))
+ {
+ mFlaggedNodes.push_back(binaryNode);
+ }
+ break;
+
+ default: break;
+ }
+ return false;
+ }
+
+ if (binaryNode->getOp() == EOpIndexDirectStruct)
+ {
+ return false;
+ }
+
+ return visit == PreVisit;
+}
+
+void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol)
+{
+ if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct)
+ {
+ mFlaggedNodes.push_back(symbol);
+ }
+}
+
+bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const
+{
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode)
+ {
+ return isInStd140InterfaceBlock(binaryNode->getLeft());
+ }
+
+ const TType &type = node->getType();
+
+ // determine if we are in the standard layout
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ return (interfaceBlock->blockStorage() == EbsStd140);
+ }
+
+ return false;
+}
+
+std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node)
+{
+ FlagStd140Structs flaggingTraversal;
+
+ node->traverse(&flaggingTraversal);
+
+ return flaggingTraversal.getFlaggedNodes();
+}
+
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h
new file mode 100644
index 00000000000..610205eb92e
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_FLAGSTD140STRUCTS_H_
+#define COMPILER_FLAGSTD140STRUCTS_H_
+
+#include "compiler/translator/intermediate.h"
+
+namespace sh
+{
+
+// This class finds references to nested structs of std140 blocks that access
+// the nested struct "by value", where the padding added in the translator
+// conflicts with the "natural" unpadded type.
+class FlagStd140Structs : public TIntermTraverser
+{
+ public:
+ const std::vector<TIntermTyped *> getFlaggedNodes() const { return mFlaggedNodes; }
+
+ protected:
+ virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode);
+ virtual void visitSymbol(TIntermSymbol *symbol);
+
+ private:
+ bool isInStd140InterfaceBlock(TIntermTyped *node) const;
+
+ std::vector<TIntermTyped *> mFlaggedNodes;
+};
+
+std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node);
+
+}
+
+#endif // COMPILER_FLAGSTD140STRUCTS_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp
new file mode 100644
index 00000000000..5cb51645593
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp
@@ -0,0 +1,82 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ForLoopUnroll.h"
+
+bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
+{
+ if (mUnrollCondition != kSamplerArrayIndex)
+ return true;
+
+ // If a sampler array index is also the loop index,
+ // 1) if the index type is integer, mark the loop for unrolling;
+ // 2) if the index type if float, set a flag to later fail compile.
+ switch (node->getOp())
+ {
+ case EOpIndexIndirect:
+ if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode())
+ {
+ TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty())
+ {
+ mVisitSamplerArrayIndexNodeInsideLoop = true;
+ node->getRight()->traverse(this);
+ mVisitSamplerArrayIndexNodeInsideLoop = false;
+ // We have already visited all the children.
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
+{
+ if (mUnrollCondition == kIntegerIndex)
+ {
+ // Check if loop index type is integer.
+ // This is called after ValidateLimitations pass, so all the calls
+ // should be valid. See ValidateLimitations::validateForLoopInit().
+ TIntermSequence& declSeq = node->getInit()->getAsAggregate()->getSequence();
+ TIntermSymbol* symbol = declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+ if (symbol->getBasicType() == EbtInt)
+ node->setUnrollFlag(true);
+ }
+
+ TIntermNode *body = node->getBody();
+ if (body != NULL)
+ {
+ mLoopStack.push(node);
+ body->traverse(this);
+ mLoopStack.pop();
+ }
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
+{
+ if (!mVisitSamplerArrayIndexNodeInsideLoop)
+ return;
+ TIntermLoop *loop = mLoopStack.findLoop(symbol);
+ if (loop)
+ {
+ switch (symbol->getBasicType())
+ {
+ case EbtFloat:
+ mSamplerArrayIndexIsFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ loop->setUnrollFlag(true);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h
new file mode 100644
index 00000000000..a820d2a20d6
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_FORLOOPUNROLL_H_
+#define COMPILER_FORLOOPUNROLL_H_
+
+#include "compiler/translator/LoopInfo.h"
+
+// This class detects for-loops that needs to be unrolled.
+// Currently we support two unroll conditions:
+// 1) kForLoopWithIntegerIndex: unroll if the index type is integer.
+// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index
+// is also the loop integer index, and reject and fail a compile
+// where a sampler array index is also the loop float index.
+class ForLoopUnrollMarker : public TIntermTraverser
+{
+ public:
+ enum UnrollCondition
+ {
+ kIntegerIndex,
+ kSamplerArrayIndex
+ };
+
+ ForLoopUnrollMarker(UnrollCondition condition)
+ : mUnrollCondition(condition),
+ mSamplerArrayIndexIsFloatLoopIndex(false),
+ mVisitSamplerArrayIndexNodeInsideLoop(false)
+ {
+ }
+
+ virtual bool visitBinary(Visit, TIntermBinary *node);
+ virtual bool visitLoop(Visit, TIntermLoop *node);
+ virtual void visitSymbol(TIntermSymbol *node);
+
+ bool samplerArrayIndexIsFloatLoopIndex() const
+ {
+ return mSamplerArrayIndexIsFloatLoopIndex;
+ }
+
+ private:
+ UnrollCondition mUnrollCondition;
+ TLoopStack mLoopStack;
+ bool mSamplerArrayIndexIsFloatLoopIndex;
+ bool mVisitSamplerArrayIndexNodeInsideLoop;
+};
+
+#endif
diff --git a/chromium/third_party/angle/src/compiler/translator/HashNames.h b/chromium/third_party/angle/src/compiler/translator/HashNames.h
new file mode 100644
index 00000000000..85161428b2a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/HashNames.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_HASH_NAMES_H_
+#define COMPILER_HASH_NAMES_H_
+
+#include <map>
+
+#include "compiler/translator/intermediate.h"
+
+#define HASHED_NAME_PREFIX "webgl_"
+
+typedef std::map<TPersistString, TPersistString> NameMap;
+
+#endif // COMPILER_HASH_NAMES_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp b/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp
new file mode 100644
index 00000000000..cd59658ff76
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InfoSink.h"
+
+void TInfoSinkBase::prefix(TPrefixType p) {
+ switch(p) {
+ case EPrefixNone:
+ break;
+ case EPrefixWarning:
+ sink.append("WARNING: ");
+ break;
+ case EPrefixError:
+ sink.append("ERROR: ");
+ break;
+ case EPrefixInternalError:
+ sink.append("INTERNAL ERROR: ");
+ break;
+ case EPrefixUnimplemented:
+ sink.append("UNIMPLEMENTED: ");
+ break;
+ case EPrefixNote:
+ sink.append("NOTE: ");
+ break;
+ default:
+ sink.append("UNKOWN ERROR: ");
+ break;
+ }
+}
+
+void TInfoSinkBase::location(int file, int line) {
+ TPersistStringStream stream;
+ if (line)
+ stream << file << ":" << line;
+ else
+ stream << file << ":? ";
+ stream << ": ";
+
+ sink.append(stream.str());
+}
+
+void TInfoSinkBase::location(const TSourceLoc& loc) {
+ location(loc.first_file, loc.first_line);
+}
+
+void TInfoSinkBase::message(TPrefixType p, const TSourceLoc& loc, const char* m) {
+ prefix(p);
+ location(loc);
+ sink.append(m);
+ sink.append("\n");
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/InfoSink.h b/chromium/third_party/angle/src/compiler/translator/InfoSink.h
new file mode 100644
index 00000000000..698a8b454b3
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InfoSink.h
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include <math.h>
+#include <stdlib.h>
+#include "compiler/translator/Common.h"
+
+// Returns the fractional part of the given floating-point number.
+inline float fractionalPart(float f) {
+ float intPart = 0.0f;
+ return modff(f, &intPart);
+}
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+ EPrefixNone,
+ EPrefixWarning,
+ EPrefixError,
+ EPrefixInternalError,
+ EPrefixUnimplemented,
+ EPrefixNote
+};
+
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+ TInfoSinkBase() {}
+
+ template <typename T>
+ TInfoSinkBase& operator<<(const T& t) {
+ TPersistStringStream stream;
+ stream << t;
+ sink.append(stream.str());
+ return *this;
+ }
+ // Override << operator for specific types. It is faster to append strings
+ // and characters directly to the sink.
+ TInfoSinkBase& operator<<(char c) {
+ sink.append(1, c);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const char* str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TPersistString& str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TString& str) {
+ sink.append(str.c_str());
+ return *this;
+ }
+ // Make sure floats are written with correct precision.
+ TInfoSinkBase& operator<<(float f) {
+ // Make sure that at least one decimal point is written. If a number
+ // does not have a fractional part, the default precision format does
+ // not write the decimal portion which gets interpreted as integer by
+ // the compiler.
+ TPersistStringStream stream;
+ if (fractionalPart(f) == 0.0f) {
+ stream.precision(1);
+ stream << std::showpoint << std::fixed << f;
+ } else {
+ stream.unsetf(std::ios::fixed);
+ stream.unsetf(std::ios::scientific);
+ stream.precision(8);
+ stream << f;
+ }
+ sink.append(stream.str());
+ return *this;
+ }
+ // Write boolean values as their names instead of integral value.
+ TInfoSinkBase& operator<<(bool b) {
+ const char* str = b ? "true" : "false";
+ sink.append(str);
+ return *this;
+ }
+
+ void erase() { sink.clear(); }
+ int size() { return static_cast<int>(sink.size()); }
+
+ const TPersistString& str() const { return sink; }
+ const char* c_str() const { return sink.c_str(); }
+
+ void prefix(TPrefixType p);
+ void location(int file, int line);
+ void location(const TSourceLoc& loc);
+ void message(TPrefixType p, const TSourceLoc& loc, const char* m);
+
+private:
+ TPersistString sink;
+};
+
+class TInfoSink {
+public:
+ TInfoSinkBase info;
+ TInfoSinkBase debug;
+ TInfoSinkBase obj;
+};
+
+#endif // _INFOSINK_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/Initialize.cpp b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp
new file mode 100644
index 00000000000..27e96f4014a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp
@@ -0,0 +1,760 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Create symbols that declare built-in definitions, add built-ins that
+// cannot be expressed in the files, and establish mappings between
+// built-in functions and operators.
+//
+
+#include "compiler/translator/Initialize.h"
+
+#include "compiler/translator/intermediate.h"
+
+void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
+{
+ TType *float1 = new TType(EbtFloat);
+ TType *float2 = new TType(EbtFloat, 2);
+ TType *float3 = new TType(EbtFloat, 3);
+ TType *float4 = new TType(EbtFloat, 4);
+
+ TType *int1 = new TType(EbtInt);
+ TType *int2 = new TType(EbtInt, 2);
+ TType *int3 = new TType(EbtInt, 3);
+ TType *int4 = new TType(EbtInt, 4);
+
+ //
+ // Angle and Trigonometric Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "radians", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "radians", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "radians", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "radians", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "degrees", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "degrees", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "degrees", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "degrees", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sin", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sin", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sin", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sin", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "cos", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "cos", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cos", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "cos", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "tan", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "tan", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "tan", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "tan", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "asin", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "asin", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "asin", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "asin", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "acos", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "acos", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "acos", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "acos", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4);
+
+ //
+ // Exponential Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "pow", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "pow", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "pow", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "pow", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp2", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp2", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp2", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp2", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log2", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log2", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log2", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log2", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sqrt", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sqrt", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sqrt", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sqrt", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "inversesqrt", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "inversesqrt", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "inversesqrt", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "inversesqrt", float4);
+
+ //
+ // Common Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "abs", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "abs", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "abs", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "abs", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sign", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sign", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sign", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sign", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "floor", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "floor", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "floor", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "floor", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "ceil", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "ceil", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "ceil", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "ceil", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "fract", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "fract", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "fract", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "fract", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mod", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "min", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "max", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "clamp", float1, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mix", float1, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "step", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float4, float4);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float1, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float1, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float1, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "smoothstep", float1, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float2, float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float3, float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float4, float4, float4);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float1, float1, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float1, float1, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float1, float1, float4);
+
+ //
+ // Geometric Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cross", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "normalize", float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "normalize", float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "normalize", float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "normalize", float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "faceforward", float1, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "faceforward", float2, float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "faceforward", float3, float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "faceforward", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "reflect", float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "reflect", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "reflect", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "reflect", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "refract", float1, float1, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "refract", float2, float2, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "refract", float3, float3, float1);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "refract", float4, float4, float1);
+
+ TType *mat2 = new TType(EbtFloat, 2, 2);
+ TType *mat3 = new TType(EbtFloat, 3, 3);
+ TType *mat4 = new TType(EbtFloat, 4, 4);
+
+ //
+ // Matrix Functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, mat2, "matrixCompMult", mat2, mat2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, mat3, "matrixCompMult", mat3, mat3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, mat4, "matrixCompMult", mat4, mat4);
+
+ TType *bool1 = new TType(EbtBool);
+ TType *bool2 = new TType(EbtBool, 2);
+ TType *bool3 = new TType(EbtBool, 3);
+ TType *bool4 = new TType(EbtBool, 4);
+
+ //
+ // Vector relational functions.
+ //
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", bool2, bool2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", bool3, bool3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", bool4, bool4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", float2, float2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", float3, float3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", int2, int2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", int3, int3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", bool2, bool2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", bool3, bool3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", bool4, bool4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool4);
+
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "not", bool2);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "not", bool3);
+ symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "not", bool4);
+
+ TType *sampler2D = new TType(EbtSampler2D);
+ TType *samplerCube = new TType(EbtSamplerCube);
+
+ //
+ // Texture Functions for GLSL ES 1.0
+ //
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3);
+
+ if (resources.OES_EGL_image_external)
+ {
+ TType *samplerExternalOES = new TType(EbtSamplerExternalOES);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float4);
+ }
+
+ if (resources.ARB_texture_rectangle)
+ {
+ TType *sampler2DRect = new TType(EbtSampler2DRect);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4);
+ }
+
+ if (resources.EXT_shader_texture_lod)
+ {
+ /* The *Grad* variants are new to both vertex and fragment shaders; the fragment
+ * shader specific pieces are added separately below.
+ */
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DGradEXT", sampler2D, float2, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeGradEXT", samplerCube, float3, float3, float3);
+ }
+
+ if (type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, float1);
+
+ if (resources.OES_standard_derivatives)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdx", float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdx", float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdx", float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdx", float4);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdy", float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdy", float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdy", float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdy", float4);
+
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "fwidth", float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "fwidth", float2);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "fwidth", float3);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "fwidth", float4);
+ }
+
+ if (resources.EXT_shader_texture_lod)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLodEXT", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLodEXT", samplerCube, float3, float1);
+ }
+ }
+
+ if(type == SH_VERTEX_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1);
+ }
+
+ TType *gvec4 = new TType(EbtGVec4);
+
+ TType *gsampler2D = new TType(EbtGSampler2D);
+ TType *gsamplerCube = new TType(EbtGSamplerCube);
+ TType *gsampler3D = new TType(EbtGSampler3D);
+ TType *gsampler2DArray = new TType(EbtGSampler2DArray);
+
+ //
+ // Texture Functions for GLSL ES 3.0
+ //
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler3D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1);
+
+ if (type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1);
+ }
+
+ TType *sampler2DShadow = new TType(EbtSampler2DShadow);
+ TType *samplerCubeShadow = new TType(EbtSamplerCubeShadow);
+ TType *sampler2DArrayShadow = new TType(EbtSampler2DArrayShadow);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DArrayShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, float1);
+
+ if (type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2D, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler3D, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsamplerCube, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler2DArray, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2DShadow, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1);
+
+ if(type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdx", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdx", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdx", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdx", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdy", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdy", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdy", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdy", float4);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "fwidth", float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "fwidth", float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "fwidth", float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "fwidth", float4);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2);
+
+ if(type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2);
+
+ if(type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2, float1);
+ }
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, float1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float3, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler3D, float4, float1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, float1);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, float1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, float2, float2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, float3, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, float4, float2, float2, int2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, float2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, float3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, float2, float2);
+
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, float2, float2, int2);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3);
+ symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2);
+
+ //
+ // Depth range in window coordinates
+ //
+ TFieldList *fields = NewPoolTFieldList();
+ TSourceLoc zeroSourceLoc = {0, 0, 0, 0};
+ TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"), zeroSourceLoc);
+ TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"), zeroSourceLoc);
+ TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"), zeroSourceLoc);
+ fields->push_back(near);
+ fields->push_back(far);
+ fields->push_back(diff);
+ TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields);
+ TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true);
+ symbolTable.insert(COMMON_BUILTINS, *depthRangeParameters);
+ TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct));
+ depthRange->setQualifier(EvqUniform);
+ symbolTable.insert(COMMON_BUILTINS, *depthRange);
+
+ //
+ // Implementation dependent built-in constants.
+ //
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits);
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors);
+
+ symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors);
+
+ if (spec != SH_CSS_SHADERS_SPEC)
+ {
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers);
+ }
+
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset);
+ symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", resources.MaxProgramTexelOffset);
+}
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources &resources,
+ TSymbolTable &symbolTable)
+{
+ //
+ // First, insert some special built-in variables that are not in
+ // the built-in header files.
+ //
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
+ symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
+ symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
+
+ //
+ // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
+ // Instead, css_MixColor and css_ColorMatrix are available.
+ //
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
+ if (resources.EXT_frag_depth) {
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1)));
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_FragDepthEXT", "GL_EXT_frag_depth");
+ }
+ } else {
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4)));
+ }
+
+ break;
+
+ case SH_VERTEX_SHADER:
+ symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
+ symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ //
+ // Next, identify which built-ins from the already loaded headers have
+ // a mapping to an operator. Those that are not identified as such are
+ // expected to be resolved through a library of functions, versus as
+ // operations.
+ //
+ symbolTable.relateToOperator(COMMON_BUILTINS, "matrixCompMult", EOpMul);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "equal", EOpVectorEqual);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "notEqual", EOpVectorNotEqual);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "lessThan", EOpLessThan);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThan", EOpGreaterThan);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "lessThanEqual", EOpLessThanEqual);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThanEqual", EOpGreaterThanEqual);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "radians", EOpRadians);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "degrees", EOpDegrees);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "sin", EOpSin);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "cos", EOpCos);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "tan", EOpTan);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "asin", EOpAsin);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "acos", EOpAcos);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "atan", EOpAtan);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "pow", EOpPow);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "exp2", EOpExp2);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "log", EOpLog);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "exp", EOpExp);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "log2", EOpLog2);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "sqrt", EOpSqrt);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "inversesqrt", EOpInverseSqrt);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "abs", EOpAbs);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "sign", EOpSign);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "floor", EOpFloor);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "ceil", EOpCeil);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "fract", EOpFract);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "mod", EOpMod);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "min", EOpMin);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "max", EOpMax);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "clamp", EOpClamp);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "mix", EOpMix);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "step", EOpStep);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "smoothstep", EOpSmoothStep);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "cross", EOpCross);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "normalize", EOpNormalize);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "faceforward", EOpFaceForward);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "reflect", EOpReflect);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "refract", EOpRefract);
+
+ symbolTable.relateToOperator(COMMON_BUILTINS, "any", EOpAny);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "all", EOpAll);
+ symbolTable.relateToOperator(COMMON_BUILTINS, "not", EOpVectorLogicalNot);
+
+ // Map language-specific operators.
+ switch(type) {
+ case SH_VERTEX_SHADER:
+ break;
+ case SH_FRAGMENT_SHADER:
+ if (resources.OES_standard_derivatives)
+ {
+ symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdx", EOpDFdx);
+ symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdy", EOpDFdy);
+ symbolTable.relateToOperator(ESSL1_BUILTINS, "fwidth", EOpFwidth);
+
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdx", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdy", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "fwidth", "GL_OES_standard_derivatives");
+ }
+ if (resources.EXT_shader_texture_lod)
+ {
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DLodEXT", "GL_EXT_shader_texture_lod");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjLodEXT", "GL_EXT_shader_texture_lod");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeLodEXT", "GL_EXT_shader_texture_lod");
+ }
+ break;
+ default: break;
+ }
+
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdx", EOpDFdx);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdy", EOpDFdy);
+ symbolTable.relateToOperator(ESSL3_BUILTINS, "fwidth", EOpFwidth);
+
+ if (resources.EXT_shader_texture_lod)
+ {
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DGradEXT", "GL_EXT_shader_texture_lod");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjGradEXT", "GL_EXT_shader_texture_lod");
+ symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeGradEXT", "GL_EXT_shader_texture_lod");
+ }
+
+ // Finally add resource-specific variables.
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ // Set up gl_FragData. The array size.
+ TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData"), fragData));
+ }
+ break;
+ default: break;
+ }
+}
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ extBehavior["GL_OES_standard_derivatives"] = EBhUndefined;
+ if (resources.OES_EGL_image_external)
+ extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
+ if (resources.ARB_texture_rectangle)
+ extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+ if (resources.EXT_draw_buffers)
+ extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
+ if (resources.EXT_frag_depth)
+ extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
+ if (resources.EXT_shader_texture_lod)
+ extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/Initialize.h b/chromium/third_party/angle/src/compiler/translator/Initialize.h
new file mode 100644
index 00000000000..b5642869aa1
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Initialize.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/ShHandle.h"
+#include "compiler/translator/SymbolTable.h"
+
+void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table);
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable);
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extensionBehavior);
+
+#endif // _INITIALIZE_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp
new file mode 100644
index 00000000000..43f81784d0a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp
@@ -0,0 +1,32 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InitializeDll.h"
+
+#include "compiler/translator/InitializeGlobals.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/osinclude.h"
+
+bool InitProcess()
+{
+ if (!InitializePoolIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize global pool");
+ return false;
+ }
+
+ if (!InitializeParseContextIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize parse context");
+ return false;
+ }
+
+ return true;
+}
+
+void DetachProcess()
+{
+ FreeParseContextIndex();
+ FreePoolIndex();
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeDll.h b/chromium/third_party/angle/src/compiler/translator/InitializeDll.h
new file mode 100644
index 00000000000..43070cc3ff7
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeDll.h
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+bool InitProcess();
+void DetachProcess();
+
+#endif // __INITIALIZEDLL_H
+
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h b/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h
new file mode 100644
index 00000000000..07159414247
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp
new file mode 100644
index 00000000000..b4defae5695
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InitializeParseContext.h"
+
+#include "compiler/translator/osinclude.h"
+
+OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializeParseContextIndex()
+{
+ assert(GlobalParseContextIndex == OS_INVALID_TLS_INDEX);
+
+ GlobalParseContextIndex = OS_AllocTLSIndex();
+ return GlobalParseContextIndex != OS_INVALID_TLS_INDEX;
+}
+
+void FreeParseContextIndex()
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+
+ OS_FreeTLSIndex(GlobalParseContextIndex);
+ GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+}
+
+void SetGlobalParseContext(TParseContext* context)
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+ OS_SetTLSValue(GlobalParseContextIndex, context);
+}
+
+TParseContext* GetGlobalParseContext()
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+ return static_cast<TParseContext*>(OS_GetTLSValue(GlobalParseContextIndex));
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h
new file mode 100644
index 00000000000..bffbab87d07
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+
+bool InitializeParseContextIndex();
+void FreeParseContextIndex();
+
+struct TParseContext;
+extern void SetGlobalParseContext(TParseContext* context);
+extern TParseContext* GetGlobalParseContext();
+
+#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp
new file mode 100644
index 00000000000..115c561c775
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/compilerdebug.h"
+
+namespace
+{
+
+TIntermConstantUnion* constructFloatConstUnionNode(const TType& type)
+{
+ TType myType = type;
+ unsigned char size = myType.getNominalSize();
+ if (myType.isMatrix())
+ size *= size;
+ ConstantUnion *u = new ConstantUnion[size];
+ for (int ii = 0; ii < size; ++ii)
+ u[ii].setFConst(0.0f);
+
+ myType.clearArrayness();
+ myType.setQualifier(EvqConst);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
+ return node;
+}
+
+TIntermConstantUnion* constructIndexNode(int index)
+{
+ ConstantUnion *u = new ConstantUnion[1];
+ u[0].setIConst(index);
+
+ TType type(EbtInt, EbpUndefined, EvqConst, 1);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+ return node;
+}
+
+} // namespace anonymous
+
+bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ bool visitChildren = !mCodeInserted;
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ break;
+ case EOpFunction:
+ {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ if (node->getName() == "main(")
+ {
+ TIntermSequence &sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermAggregate *body = NULL;
+ if (sequence.size() == 1)
+ {
+ body = new TIntermAggregate(EOpSequence);
+ sequence.push_back(body);
+ }
+ else
+ {
+ body = sequence[1]->getAsAggregate();
+ }
+ ASSERT(body);
+ insertInitCode(body->getSequence());
+ mCodeInserted = true;
+ }
+ break;
+ }
+ default:
+ visitChildren = false;
+ break;
+ }
+ return visitChildren;
+}
+
+void InitializeVariables::insertInitCode(TIntermSequence& sequence)
+{
+ for (size_t ii = 0; ii < mVariables.size(); ++ii)
+ {
+ const InitVariableInfo& varInfo = mVariables[ii];
+
+ if (varInfo.type.isArray())
+ {
+ for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index)
+ {
+ TIntermBinary *assign = new TIntermBinary(EOpAssign);
+ sequence.insert(sequence.begin(), assign);
+
+ TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
+ TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
+ indexDirect->setLeft(symbol);
+ TIntermConstantUnion *indexNode = constructIndexNode(index);
+ indexDirect->setRight(indexNode);
+
+ assign->setLeft(indexDirect);
+
+ TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
+ assign->setRight(zeroConst);
+ }
+ }
+ else
+ {
+ TIntermBinary *assign = new TIntermBinary(EOpAssign);
+ sequence.insert(sequence.begin(), assign);
+ TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
+ assign->setLeft(symbol);
+ TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
+ assign->setRight(zeroConst);
+ }
+
+ }
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h
new file mode 100644
index 00000000000..1cd6d7e1b51
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_INITIALIZE_VARIABLES_H_
+#define COMPILER_INITIALIZE_VARIABLES_H_
+
+#include "compiler/translator/intermediate.h"
+
+class InitializeVariables : public TIntermTraverser
+{
+ public:
+ struct InitVariableInfo
+ {
+ TString name;
+ TType type;
+
+ InitVariableInfo(const TString& _name, const TType& _type)
+ : name(_name),
+ type(_type)
+ {
+ }
+ };
+ typedef TVector<InitVariableInfo> InitVariableInfoList;
+
+ InitializeVariables(const InitVariableInfoList& vars)
+ : mCodeInserted(false),
+ mVariables(vars)
+ {
+ }
+
+ protected:
+ virtual bool visitBinary(Visit visit, TIntermBinary* node) { return false; }
+ virtual bool visitUnary(Visit visit, TIntermUnary* node) { return false; }
+ virtual bool visitSelection(Visit visit, TIntermSelection* node) { return false; }
+ virtual bool visitLoop(Visit visit, TIntermLoop* node) { return false; }
+ virtual bool visitBranch(Visit visit, TIntermBranch* node) { return false; }
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
+
+ private:
+ void insertInitCode(TIntermSequence& sequence);
+
+ InitVariableInfoList mVariables;
+ bool mCodeInserted;
+};
+
+#endif // COMPILER_INITIALIZE_VARIABLES_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp
new file mode 100644
index 00000000000..69f87c32847
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp
@@ -0,0 +1,263 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/intermediate.h"
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+// preVisit, postVisit, and rightToLeft control what order
+// nodes are visited in.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+ it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+ it->visitConstantUnion(this);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if (it->preVisit)
+ visit = it->visitBinary(PreVisit, this);
+
+ //
+ // Visit the children, in the right order.
+ //
+ if (visit)
+ {
+ it->incrementDepth(this);
+
+ if (it->rightToLeft)
+ {
+ if (right)
+ right->traverse(it);
+
+ if (it->inVisit)
+ visit = it->visitBinary(InVisit, this);
+
+ if (visit && left)
+ left->traverse(it);
+ }
+ else
+ {
+ if (left)
+ left->traverse(it);
+
+ if (it->inVisit)
+ visit = it->visitBinary(InVisit, this);
+
+ if (visit && right)
+ right->traverse(it);
+ }
+
+ it->decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if (visit && it->postVisit)
+ it->visitBinary(PostVisit, this);
+}
+
+//
+// Traverse a unary node. Same comments in binary node apply here.
+//
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitUnary(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth(this);
+ operand->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitUnary(PostVisit, this);
+}
+
+//
+// Traverse an aggregate node. Same comments in binary node apply here.
+//
+void TIntermAggregate::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitAggregate(PreVisit, this);
+
+ if (visit)
+ {
+ it->incrementDepth(this);
+
+ if (it->rightToLeft)
+ {
+ for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if (visit && it->inVisit)
+ {
+ if (*sit != sequence.front())
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if (visit && it->inVisit)
+ {
+ if (*sit != sequence.back())
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitAggregate(PostVisit, this);
+}
+
+//
+// Traverse a selection node. Same comments in binary node apply here.
+//
+void TIntermSelection::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitSelection(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth(this);
+ if (it->rightToLeft) {
+ if (falseBlock)
+ falseBlock->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ condition->traverse(it);
+ } else {
+ condition->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ if (falseBlock)
+ falseBlock->traverse(it);
+ }
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitSelection(PostVisit, this);
+}
+
+//
+// Traverse a loop node. Same comments in binary node apply here.
+//
+void TIntermLoop::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitLoop(PreVisit, this);
+
+ if (visit)
+ {
+ it->incrementDepth(this);
+
+ if (it->rightToLeft)
+ {
+ if (expr)
+ expr->traverse(it);
+
+ if (body)
+ body->traverse(it);
+
+ if (cond)
+ cond->traverse(it);
+
+ if (init)
+ init->traverse(it);
+ }
+ else
+ {
+ if (init)
+ init->traverse(it);
+
+ if (cond)
+ cond->traverse(it);
+
+ if (body)
+ body->traverse(it);
+
+ if (expr)
+ expr->traverse(it);
+ }
+
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitLoop(PostVisit, this);
+}
+
+//
+// Traverse a branch node. Same comments in binary node apply here.
+//
+void TIntermBranch::traverse(TIntermTraverser *it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitBranch(PreVisit, this);
+
+ if (visit && expression) {
+ it->incrementDepth(this);
+ expression->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitBranch(PostVisit, this);
+}
+
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+ it->visitRaw(this);
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp
new file mode 100644
index 00000000000..9df2afc53c2
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp
@@ -0,0 +1,1835 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/localintermediate.h"
+#include "compiler/translator/QualifierAlive.h"
+#include "compiler/translator/RemoveTree.h"
+#include "compiler/translator/SymbolTable.h"
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
+
+static TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
+{
+ return left > right ? left : right;
+}
+
+const char* getOperatorString(TOperator op)
+{
+ switch (op) {
+ case EOpInitialize: return "=";
+ case EOpAssign: return "=";
+ case EOpAddAssign: return "+=";
+ case EOpSubAssign: return "-=";
+ case EOpDivAssign: return "/=";
+
+ // Fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign: return "*=";
+
+ // Fall-through.
+ case EOpIndexDirect:
+ case EOpIndexIndirect: return "[]";
+
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock: return ".";
+ case EOpVectorSwizzle: return ".";
+ case EOpAdd: return "+";
+ case EOpSub: return "-";
+ case EOpMul: return "*";
+ case EOpDiv: return "/";
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: return "==";
+ case EOpNotEqual: return "!=";
+ case EOpLessThan: return "<";
+ case EOpGreaterThan: return ">";
+ case EOpLessThanEqual: return "<=";
+ case EOpGreaterThanEqual: return ">=";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix: return "*";
+
+ case EOpLogicalOr: return "||";
+ case EOpLogicalXor: return "^^";
+ case EOpLogicalAnd: return "&&";
+ case EOpNegative: return "-";
+ case EOpVectorLogicalNot: return "not";
+ case EOpLogicalNot: return "!";
+ case EOpPostIncrement: return "++";
+ case EOpPostDecrement: return "--";
+ case EOpPreIncrement: return "++";
+ case EOpPreDecrement: return "--";
+
+ // Fall-through.
+ case EOpConvIntToBool:
+ case EOpConvUIntToBool:
+ case EOpConvFloatToBool: return "bool";
+
+ // Fall-through.
+ case EOpConvBoolToFloat:
+ case EOpConvUIntToFloat:
+ case EOpConvIntToFloat: return "float";
+
+ // Fall-through.
+ case EOpConvFloatToInt:
+ case EOpConvUIntToInt:
+ case EOpConvBoolToInt: return "int";
+
+ // Fall-through.
+ case EOpConvIntToUInt:
+ case EOpConvFloatToUInt:
+ case EOpConvBoolToUInt: return "uint";
+
+ case EOpRadians: return "radians";
+ case EOpDegrees: return "degrees";
+ case EOpSin: return "sin";
+ case EOpCos: return "cos";
+ case EOpTan: return "tan";
+ case EOpAsin: return "asin";
+ case EOpAcos: return "acos";
+ case EOpAtan: return "atan";
+ case EOpExp: return "exp";
+ case EOpLog: return "log";
+ case EOpExp2: return "exp2";
+ case EOpLog2: return "log2";
+ case EOpSqrt: return "sqrt";
+ case EOpInverseSqrt: return "inversesqrt";
+ case EOpAbs: return "abs";
+ case EOpSign: return "sign";
+ case EOpFloor: return "floor";
+ case EOpCeil: return "ceil";
+ case EOpFract: return "fract";
+ case EOpLength: return "length";
+ case EOpNormalize: return "normalize";
+ case EOpDFdx: return "dFdx";
+ case EOpDFdy: return "dFdy";
+ case EOpFwidth: return "fwidth";
+ case EOpAny: return "any";
+ case EOpAll: return "all";
+
+ default: break;
+ }
+ return "";
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
+{
+ TIntermSymbol* node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
+{
+ switch (op) {
+ case EOpEqual:
+ case EOpNotEqual:
+ if (left->isArray())
+ return 0;
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
+ return 0;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
+ return 0;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+ return 0;
+ default: break;
+ }
+
+ //
+ // First try converting the children to compatible types.
+ //
+ if (left->getType().getStruct() && right->getType().getStruct()) {
+ if (left->getType() != right->getType())
+ return 0;
+ } else {
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child)
+ right = child;
+ else {
+ child = addConversion(op, right->getType(), left);
+ if (child)
+ left = child;
+ else
+ return 0;
+ }
+ }
+
+ //
+ // Need a new node holding things together then. Make
+ // one and promote it to the right type.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+
+ node->setLeft(left);
+ node->setRight(right);
+ if (!node->promote(infoSink))
+ return 0;
+
+ //
+ // See if we can fold constants.
+ //
+ TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+ TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+ if (leftTempConstant && rightTempConstant) {
+ TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
+
+ if (typedReturnNode)
+ return typedReturnNode;
+ }
+
+ return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
+{
+ //
+ // Like adding binary math, except the conversion can only go
+ // from right to left.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child == 0)
+ return 0;
+
+ node->setLeft(left);
+ node->setRight(child);
+ if (! node->promote(infoSink))
+ return 0;
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
+{
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+ node->setLeft(base);
+ node->setRight(index);
+
+ // caller should set the type
+
+ return node;
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line)
+{
+ TIntermUnary* node;
+ TIntermTyped* child = childNode->getAsTyped();
+
+ if (child == 0) {
+ infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
+ return 0;
+ }
+
+ switch (op) {
+ case EOpLogicalNot:
+ if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+ return 0;
+ }
+ break;
+
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+ return 0;
+ default: break;
+ }
+
+ //
+ // Do we need to promote the operand?
+ //
+ // Note: Implicit promotions were removed from the language.
+ //
+ TBasicType newType = EbtVoid;
+ switch (op) {
+ case EOpConstructInt: newType = EbtInt; break;
+ case EOpConstructUInt: newType = EbtUInt; break;
+ case EOpConstructBool: newType = EbtBool; break;
+ case EOpConstructFloat: newType = EbtFloat; break;
+ default: break;
+ }
+
+ if (newType != EbtVoid) {
+ child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
+ child->getNominalSize(),
+ child->getSecondarySize(),
+ child->isArray()),
+ child);
+ if (child == 0)
+ return 0;
+ }
+
+ //
+ // For constructors, we are now done, it's all in the conversion.
+ //
+ switch (op) {
+ case EOpConstructInt:
+ case EOpConstructUInt:
+ case EOpConstructBool:
+ case EOpConstructFloat:
+ return child;
+ default: break;
+ }
+
+ TIntermConstantUnion *childTempConstant = 0;
+ if (child->getAsConstantUnion())
+ childTempConstant = child->getAsConstantUnion();
+
+ //
+ // Make a new node for the operator.
+ //
+ node = new TIntermUnary(op);
+ node->setLine(line);
+ node->setOperand(child);
+
+ if (! node->promote(infoSink))
+ return 0;
+
+ if (childTempConstant) {
+ TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
+
+ if (newChild)
+ return newChild;
+ }
+
+ return node;
+}
+
+//
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters. Sequences
+// of instructions are also aggregates, but they just direnctly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate but no operator was set.
+//
+TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
+{
+ TIntermAggregate* aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node) {
+ aggNode = node->getAsAggregate();
+ if (aggNode == 0 || aggNode->getOp() != EOpNull) {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence().push_back(node);
+ }
+ } else
+ aggNode = new TIntermAggregate();
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Convert one type to another.
+//
+// Returns the node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Return 0 if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+ //
+ // Does the base type allow operation?
+ //
+ if (node->getBasicType() == EbtVoid ||
+ IsSampler(node->getBasicType()))
+ {
+ return 0;
+ }
+
+ //
+ // Otherwise, if types are identical, no problem
+ //
+ if (type == node->getType())
+ return node;
+
+ //
+ // If one's a structure, then no conversions.
+ //
+ if (type.getStruct() || node->getType().getStruct())
+ return 0;
+
+ //
+ // If one's an array, then no conversions.
+ //
+ if (type.isArray() || node->getType().isArray())
+ return 0;
+
+ TBasicType promoteTo;
+
+ switch (op) {
+ //
+ // Explicit conversions
+ //
+ case EOpConstructBool:
+ promoteTo = EbtBool;
+ break;
+ case EOpConstructFloat:
+ promoteTo = EbtFloat;
+ break;
+ case EOpConstructInt:
+ promoteTo = EbtInt;
+ break;
+ case EOpConstructUInt:
+ promoteTo = EbtUInt;
+ break;
+ default:
+ //
+ // implicit conversions were removed from the language.
+ //
+ if (type.getBasicType() != node->getType().getBasicType())
+ return 0;
+ //
+ // Size and structure could still differ, but that's
+ // handled by operator promotion.
+ //
+ return node;
+ }
+
+ if (node->getAsConstantUnion()) {
+
+ return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
+ } else {
+
+ //
+ // Add a new newNode for the conversion.
+ //
+ TIntermUnary* newNode = 0;
+
+ TOperator newOp = EOpNull;
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToFloat; break;
+ case EbtUInt: newOp = EOpConvFloatToUInt; break;
+ case EbtBool: newOp = EOpConvBoolToFloat; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToBool; break;
+ case EbtUInt: newOp = EOpConvBoolToUInt; break;
+ case EbtFloat: newOp = EOpConvFloatToBool; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getBasicType()) {
+ case EbtUInt: newOp = EOpConvUIntToInt; break;
+ case EbtBool: newOp = EOpConvBoolToInt; break;
+ case EbtFloat: newOp = EOpConvFloatToInt; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ case EbtUInt:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToUInt; break;
+ case EbtBool: newOp = EOpConvBoolToUInt; break;
+ case EbtFloat: newOp = EOpConvFloatToUInt; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
+ return 0;
+ }
+
+ TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->getSecondarySize(), node->isArray());
+ newNode = new TIntermUnary(newOp, type);
+ newNode->setLine(node->getLine());
+ newNode->setOperand(node);
+
+ return newNode;
+ }
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
+{
+ if (left == 0 && right == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = 0;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull) {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence().push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence().push_back(right);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless 0 was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = new TIntermAggregate;
+ aggNode->getSequence().push_back(node);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the selection node created.
+//
+TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
+{
+ //
+ // For compile time constant selections, prune the code and
+ // test now.
+ //
+
+ if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
+ else
+ return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
+ }
+
+ TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+ node->setLine(line);
+
+ return node;
+}
+
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
+{
+ if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
+ return right;
+ } else {
+ TIntermTyped *commaAggregate = growAggregate(left, right, line);
+ commaAggregate->getAsAggregate()->setOp(EOpComma);
+ commaAggregate->setType(right->getType());
+ commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
+ return commaAggregate;
+ }
+}
+
+//
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the selection node created, or 0 if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
+{
+ //
+ // Get compatible types.
+ //
+ TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
+ if (child)
+ falseBlock = child;
+ else {
+ child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
+ if (child)
+ trueBlock = child;
+ else
+ return 0;
+ }
+
+ //
+ // See if all the operands are constant, then fold it otherwise not.
+ //
+
+ if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getBConst(0))
+ return trueBlock;
+ else
+ return falseBlock;
+ }
+
+ //
+ // Make a selection node.
+ //
+ TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+ node->getTypePointer()->setQualifier(EvqTemporary);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
+{
+ TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
+{
+
+ TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+ node->setLine(line);
+ TIntermConstantUnion* constIntNode;
+ TIntermSequence &sequenceVector = node->getSequence();
+ ConstantUnion* unionArray;
+
+ for (int i = 0; i < fields.num; i++) {
+ unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[i]);
+ constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
+ sequenceVector.push_back(constIntNode);
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
+{
+ TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
+{
+ TIntermBranch* node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// This is to be executed once the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root)
+{
+ if (root == 0)
+ return true;
+
+ //
+ // First, finish off the top level sequence, if any
+ //
+ TIntermAggregate* aggRoot = root->getAsAggregate();
+ if (aggRoot && aggRoot->getOp() == EOpNull)
+ aggRoot->setOp(EOpSequence);
+
+ return true;
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::remove(TIntermNode* root)
+{
+ if (root)
+ RemoveAllTreeNodes(root);
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+#define REPLACE_IF_IS(node, type, original, replacement) \
+ if (node == original) { \
+ node = static_cast<type *>(replacement); \
+ return true; \
+ }
+
+bool TIntermLoop::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(init, TIntermNode, original, replacement);
+ REPLACE_IF_IS(cond, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(expr, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(body, TIntermNode, original, replacement);
+ return false;
+}
+
+void TIntermLoop::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ if (init)
+ {
+ nodeQueue->push(init);
+ }
+ if (cond)
+ {
+ nodeQueue->push(cond);
+ }
+ if (expr)
+ {
+ nodeQueue->push(expr);
+ }
+ if (body)
+ {
+ nodeQueue->push(body);
+ }
+}
+
+bool TIntermBranch::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(expression, TIntermTyped, original, replacement);
+ return false;
+}
+
+void TIntermBranch::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ if (expression)
+ {
+ nodeQueue->push(expression);
+ }
+}
+
+bool TIntermBinary::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(left, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(right, TIntermTyped, original, replacement);
+ return false;
+}
+
+void TIntermBinary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ if (left)
+ {
+ nodeQueue->push(left);
+ }
+ if (right)
+ {
+ nodeQueue->push(right);
+ }
+}
+
+bool TIntermUnary::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(operand, TIntermTyped, original, replacement);
+ return false;
+}
+
+void TIntermUnary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ if (operand)
+ {
+ nodeQueue->push(operand);
+ }
+}
+
+bool TIntermAggregate::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ for (size_t ii = 0; ii < sequence.size(); ++ii)
+ {
+ REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement);
+ }
+ return false;
+}
+
+void TIntermAggregate::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ for (size_t childIndex = 0; childIndex < sequence.size(); childIndex++)
+ {
+ nodeQueue->push(sequence[childIndex]);
+ }
+}
+
+bool TIntermSelection::replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(condition, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement);
+ REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement);
+ return false;
+}
+
+void TIntermSelection::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const
+{
+ if (condition)
+ {
+ nodeQueue->push(condition);
+ }
+ if (trueBlock)
+ {
+ nodeQueue->push(trueBlock);
+ }
+ if (falseBlock)
+ {
+ nodeQueue->push(falseBlock);
+ }
+}
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+bool TIntermOperator::isAssignment() const
+{
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ case EOpConstructUVec2:
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+ case EOpConstructUInt:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ case EOpConstructStruct:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//
+// Make sure the type of a unary operator is appropriate for its
+// combination of operation and operand type.
+//
+// Returns false in nothing makes sense.
+//
+bool TIntermUnary::promote(TInfoSink&)
+{
+ switch (op) {
+ case EOpLogicalNot:
+ if (operand->getBasicType() != EbtBool)
+ return false;
+ break;
+ case EOpNegative:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ if (operand->getBasicType() == EbtBool)
+ return false;
+ break;
+
+ // operators for built-ins are already type checked against their prototype
+ case EOpAny:
+ case EOpAll:
+ case EOpVectorLogicalNot:
+ return true;
+
+ default:
+ if (operand->getBasicType() != EbtFloat)
+ return false;
+ }
+
+ setType(operand->getType());
+ type.setQualifier(EvqTemporary);
+
+ return true;
+}
+
+bool validateMultiplication(TOperator op, const TType &left, const TType &right)
+{
+ switch (op)
+ {
+ case EOpMul:
+ case EOpMulAssign:
+ return left.getNominalSize() == right.getNominalSize() && left.getSecondarySize() == right.getSecondarySize();
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesScalarAssign:
+ return true;
+ case EOpVectorTimesMatrix:
+ return left.getNominalSize() == right.getRows();
+ case EOpVectorTimesMatrixAssign:
+ return left.getNominalSize() == right.getRows() && left.getNominalSize() == right.getCols();
+ case EOpMatrixTimesVector:
+ return left.getCols() == right.getNominalSize();
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesScalarAssign:
+ return true;
+ case EOpMatrixTimesMatrix:
+ return left.getCols() == right.getRows();
+ case EOpMatrixTimesMatrixAssign:
+ return left.getCols() == right.getCols() && left.getRows() == right.getRows();
+
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+//
+// Establishes the type of the resultant operation, as well as
+// makes the operator the correct one for the operands.
+//
+// Returns false if operator can't work on operands.
+//
+bool TIntermBinary::promote(TInfoSink& infoSink)
+{
+ // This function only handles scalars, vectors, and matrices.
+ if (left->isArray() || right->isArray())
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
+ return false;
+ }
+
+ // GLSL ES 2.0 does not support implicit type casting.
+ // So the basic type should always match.
+ if (left->getBasicType() != right->getBasicType())
+ return false;
+
+ //
+ // Base assumption: just make the type the same as the left
+ // operand. Then only deviations from this need be coded.
+ //
+ setType(left->getType());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst)
+ {
+ getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ const int nominalSize = std::max(left->getNominalSize(), right->getNominalSize());
+
+ //
+ // All scalars or structs. Code after this test assumes this case is removed!
+ //
+ if (nominalSize == 1)
+ {
+ switch (op)
+ {
+ //
+ // Promote to conditional
+ //
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ //
+ // And and Or operate on conditionals
+ //
+ case EOpLogicalAnd:
+ case EOpLogicalOr:
+ // Both operands must be of type bool.
+ if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
+ {
+ return false;
+ }
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
+ // Can these two operands be combined?
+ //
+ TBasicType basicType = left->getBasicType();
+ switch (op)
+ {
+ case EOpMul:
+ if (!left->isMatrix() && right->isMatrix())
+ {
+ if (left->isVector())
+ {
+ op = EOpVectorTimesMatrix;
+ setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), 1));
+ }
+ else
+ {
+ op = EOpMatrixTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), right->getRows()));
+ }
+ }
+ else if (left->isMatrix() && !right->isMatrix())
+ {
+ if (right->isVector())
+ {
+ op = EOpMatrixTimesVector;
+ setType(TType(basicType, higherPrecision, EvqTemporary, left->getRows(), 1));
+ }
+ else
+ {
+ op = EOpMatrixTimesScalar;
+ }
+ }
+ else if (left->isMatrix() && right->isMatrix())
+ {
+ op = EOpMatrixTimesMatrix;
+ setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), left->getRows()));
+ }
+ else if (!left->isMatrix() && !right->isMatrix())
+ {
+ if (left->isVector() && right->isVector())
+ {
+ // leave as component product
+ }
+ else if (left->isVector() || right->isVector())
+ {
+ op = EOpVectorTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1));
+ }
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
+ return false;
+ }
+
+ if (!validateMultiplication(op, left->getType(), right->getType()))
+ {
+ return false;
+ }
+ break;
+
+ case EOpMulAssign:
+ if (!left->isMatrix() && right->isMatrix())
+ {
+ if (left->isVector())
+ {
+ op = EOpVectorTimesMatrixAssign;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (left->isMatrix() && !right->isMatrix())
+ {
+ if (right->isVector())
+ {
+ return false;
+ }
+ else
+ {
+ op = EOpMatrixTimesScalarAssign;
+ }
+ }
+ else if (left->isMatrix() && right->isMatrix())
+ {
+ op = EOpMatrixTimesMatrixAssign;
+ setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), left->getRows()));
+ }
+ else if (!left->isMatrix() && !right->isMatrix())
+ {
+ if (left->isVector() && right->isVector())
+ {
+ // leave as component product
+ }
+ else if (left->isVector() || right->isVector())
+ {
+ if (! left->isVector())
+ return false;
+ op = EOpVectorTimesScalarAssign;
+ setType(TType(basicType, higherPrecision, EvqTemporary, left->getNominalSize(), 1));
+ }
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
+ return false;
+ }
+
+ if (!validateMultiplication(op, left->getType(), right->getType()))
+ {
+ return false;
+ }
+ break;
+
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ {
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+
+ // Are the sizes compatible?
+ if (left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize())
+ {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (!left->isScalar() && !right->isScalar())
+ return false;
+
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
+
+ const int secondarySize = std::max(left->getSecondarySize(), right->getSecondarySize());
+
+ setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize));
+ }
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->getNominalSize() != right->getNominalSize()) ||
+ (left->getSecondarySize() != right->getSecondarySize()))
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ const TFieldList& fields = leftNodeType.getStruct()->fields();
+
+ size_t structSize = fields.size();
+ size_t index = 0;
+
+ for (size_t j = 0; j < structSize; j++) {
+ size_t size = fields[j]->type()->getObjectSize();
+ for (size_t i = 0; i < size; i++) {
+ if (fields[j]->type()->getBasicType() == EbtStruct) {
+ if (!CompareStructure(*fields[j]->type(), &rightUnionArray[index], &leftUnionArray[index]))
+ return false;
+ } else {
+ if (leftUnionArray[index] != rightUnionArray[index])
+ return false;
+ index++;
+ }
+
+ }
+ }
+ return true;
+}
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ if (leftNodeType.isArray()) {
+ TType typeWithoutArrayness = leftNodeType;
+ typeWithoutArrayness.clearArrayness();
+
+ size_t arraySize = leftNodeType.getArraySize();
+
+ for (size_t i = 0; i < arraySize; ++i) {
+ size_t offset = typeWithoutArrayness.getObjectSize() * i;
+ if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
+ return false;
+ }
+ } else
+ return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
+
+ return true;
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
+{
+ ConstantUnion *unionArray = getUnionArrayPointer();
+
+ if (!unionArray)
+ return 0;
+
+ size_t objectSize = getType().getObjectSize();
+
+ if (constantNode)
+ {
+ // binary operations
+ TIntermConstantUnion *node = constantNode->getAsConstantUnion();
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ TType returnType = getType();
+
+ if (!rightUnionArray)
+ return 0;
+
+ // for a case like float f = 1.2 + vec4(2,3,4,5);
+ if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
+ {
+ rightUnionArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; ++i)
+ {
+ rightUnionArray[i] = *node->getUnionArrayPointer();
+ }
+ returnType = getType();
+ }
+ else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
+ {
+ // for a case like float f = vec4(2,3,4,5) + 1.2;
+ unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
+ for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
+ {
+ unionArray[i] = *getUnionArrayPointer();
+ }
+ returnType = node->getType();
+ objectSize = constantNode->getType().getObjectSize();
+ }
+
+ ConstantUnion* tempConstArray = 0;
+ TIntermConstantUnion *tempNode;
+
+ bool boolNodeFlag = false;
+ switch(op) {
+ case EOpAdd:
+ tempConstArray = new ConstantUnion[objectSize];
+ {
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] + rightUnionArray[i];
+ }
+ break;
+ case EOpSub:
+ tempConstArray = new ConstantUnion[objectSize];
+ {
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] - rightUnionArray[i];
+ }
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ tempConstArray = new ConstantUnion[objectSize];
+ {
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] * rightUnionArray[i];
+ }
+ break;
+
+ case EOpMatrixTimesMatrix:
+ {
+ if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat)
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
+ return 0;
+ }
+
+ const int leftCols = getCols();
+ const int leftRows = getRows();
+ const int rightCols = constantNode->getType().getCols();
+ const int rightRows = constantNode->getType().getRows();
+ const int resultCols = rightCols;
+ const int resultRows = leftRows;
+
+ tempConstArray = new ConstantUnion[resultCols*resultRows];
+ for (int row = 0; row < resultRows; row++)
+ {
+ for (int column = 0; column < resultCols; column++)
+ {
+ tempConstArray[resultRows * column + row].setFConst(0.0f);
+ for (int i = 0; i < leftCols; i++)
+ {
+ tempConstArray[resultRows * column + row].setFConst(tempConstArray[resultRows * column + row].getFConst() + unionArray[i * leftRows + row].getFConst() * (rightUnionArray[column * rightRows + i].getFConst()));
+ }
+ }
+ }
+
+ // update return type for matrix product
+ returnType.setPrimarySize(resultCols);
+ returnType.setSecondarySize(resultRows);
+ }
+ break;
+
+ case EOpDiv:
+ {
+ tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ if (rightUnionArray[i] == 0.0f)
+ {
+ infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
+ tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
+ }
+ else
+ {
+ tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
+ }
+ break;
+
+ case EbtInt:
+ if (rightUnionArray[i] == 0)
+ {
+ infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
+ tempConstArray[i].setIConst(INT_MAX);
+ }
+ else
+ {
+ tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
+ }
+ break;
+
+ case EbtUInt:
+ if (rightUnionArray[i] == 0)
+ {
+ infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
+ tempConstArray[i].setUConst(UINT_MAX);
+ }
+ else
+ {
+ tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
+ }
+ break;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ {
+ if (node->getBasicType() != EbtFloat)
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
+ return 0;
+ }
+
+ const int matrixCols = getCols();
+ const int matrixRows = getRows();
+
+ tempConstArray = new ConstantUnion[matrixRows];
+
+ for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
+ {
+ tempConstArray[matrixRow].setFConst(0.0f);
+ for (int col = 0; col < matrixCols; col++)
+ {
+ tempConstArray[matrixRow].setFConst(tempConstArray[matrixRow].getFConst() + ((unionArray[col * matrixRows + matrixRow].getFConst()) * rightUnionArray[col].getFConst()));
+ }
+ }
+
+ returnType = node->getType();
+ returnType.setPrimarySize(matrixRows);
+
+ tempNode = new TIntermConstantUnion(tempConstArray, returnType);
+ tempNode->setLine(getLine());
+
+ return tempNode;
+ }
+
+ case EOpVectorTimesMatrix:
+ {
+ if (getType().getBasicType() != EbtFloat)
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
+ return 0;
+ }
+
+ const int matrixCols = constantNode->getType().getCols();
+ const int matrixRows = constantNode->getType().getRows();
+
+ tempConstArray = new ConstantUnion[matrixCols];
+
+ for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
+ {
+ tempConstArray[matrixCol].setFConst(0.0f);
+ for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
+ {
+ tempConstArray[matrixCol].setFConst(tempConstArray[matrixCol].getFConst() + ((unionArray[matrixRow].getFConst()) * rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst()));
+ }
+ }
+
+ returnType.setPrimarySize(matrixCols);
+ }
+ break;
+
+ case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+ {
+ tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ tempConstArray[i] = unionArray[i] && rightUnionArray[i];
+ }
+ }
+ break;
+
+ case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+ {
+ tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ tempConstArray[i] = unionArray[i] || rightUnionArray[i];
+ }
+ }
+ break;
+
+ case EOpLogicalXor:
+ {
+ tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ switch (getType().getBasicType())
+ {
+ case EbtBool:
+ tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpLessThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray < *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+
+ case EOpGreaterThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray > *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+
+ case EOpLessThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray > *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+
+ case EOpGreaterThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray < *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+
+ case EOpEqual:
+ if (getType().getBasicType() == EbtStruct)
+ {
+ if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ }
+ else
+ {
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (unionArray[i] != rightUnionArray[i])
+ {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag)
+ {
+ tempConstArray->setBConst(true);
+ }
+ else
+ {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpNotEqual:
+ if (getType().getBasicType() == EbtStruct)
+ {
+ if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ }
+ else
+ {
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (unionArray[i] == rightUnionArray[i])
+ {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag)
+ {
+ tempConstArray->setBConst(true);
+ }
+ else
+ {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
+ return 0;
+ }
+ tempNode = new TIntermConstantUnion(tempConstArray, returnType);
+ tempNode->setLine(getLine());
+
+ return tempNode;
+ }
+ else
+ {
+ //
+ // Do unary operations
+ //
+ TIntermConstantUnion *newNode = 0;
+ ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ switch(op)
+ {
+ case EOpNegative:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
+ case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+ case EbtUInt: tempConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return 0;
+ }
+ break;
+
+ case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
+ switch (getType().getBasicType())
+ {
+ case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return 0;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ newNode = new TIntermConstantUnion(tempConstArray, getType());
+ newNode->setLine(getLine());
+ return newNode;
+ }
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
+{
+ size_t size = node->getType().getObjectSize();
+
+ ConstantUnion *leftUnionArray = new ConstantUnion[size];
+
+ for (size_t i=0; i < size; i++) {
+
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
+ break;
+ case EbtUInt:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getUConst(i)));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
+ break;
+ case EbtUInt:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getUConst(i)));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+ break;
+ case EbtUInt:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getIConst(i)));
+ break;
+ case EbtUInt:
+ leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getUConst(i)));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getBConst(i)));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getFConst(i)));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setBConst(node->getIConst(i) != 0);
+ break;
+ case EbtUInt:
+ leftUnionArray[i].setBConst(node->getUConst(i) != 0);
+ break;
+ case EbtBool:
+ leftUnionArray[i].setBConst(node->getBConst(i));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
+ return 0;
+ }
+
+ }
+
+ const TType& t = node->getType();
+
+ return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine());
+}
+
+// static
+TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
+{
+ if (hashFunction == NULL || name.empty())
+ return name;
+ khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
+ TStringStream stream;
+ stream << HASHED_NAME_PREFIX << std::hex << number;
+ TString hashedName = stream.str();
+ return hashedName;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp b/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp
new file mode 100644
index 00000000000..226f1b23807
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp
@@ -0,0 +1,211 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/LoopInfo.h"
+
+namespace
+{
+
+int EvaluateIntConstant(TIntermConstantUnion *node)
+{
+ ASSERT(node && node->getUnionArrayPointer());
+ return node->getIConst(0);
+}
+
+int GetLoopIntIncrement(TIntermLoop *node)
+{
+ TIntermNode *expr = node->getExpression();
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary *unOp = expr->getAsUnaryNode();
+ TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermConstantUnion *incrementNode = NULL;
+ if (unOp)
+ {
+ op = unOp->getOp();
+ }
+ else if (binOp)
+ {
+ op = binOp->getOp();
+ ASSERT(binOp->getRight());
+ incrementNode = binOp->getRight()->getAsConstantUnion();
+ ASSERT(incrementNode);
+ }
+
+ int increment = 0;
+ // The operator is one of: ++ -- += -=.
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ ASSERT(unOp && !binOp);
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ ASSERT(unOp && !binOp);
+ increment = -1;
+ break;
+ case EOpAddAssign:
+ ASSERT(!unOp && binOp);
+ increment = EvaluateIntConstant(incrementNode);
+ break;
+ case EOpSubAssign:
+ ASSERT(!unOp && binOp);
+ increment = - EvaluateIntConstant(incrementNode);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return increment;
+}
+
+} // namespace anonymous
+
+TLoopIndexInfo::TLoopIndexInfo()
+ : mId(-1),
+ mType(EbtVoid),
+ mInitValue(0),
+ mStopValue(0),
+ mIncrementValue(0),
+ mOp(EOpNull),
+ mCurrentValue(0)
+{
+}
+
+void TLoopIndexInfo::fillInfo(TIntermLoop *node)
+{
+ if (node == NULL)
+ return;
+
+ // Here we assume all the operations are valid, because the loop node is
+ // already validated in ValidateLimitations.
+ TIntermSequence &declSeq =
+ node->getInit()->getAsAggregate()->getSequence();
+ TIntermBinary *declInit = declSeq[0]->getAsBinaryNode();
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+
+ mId = symbol->getId();
+ mType = symbol->getBasicType();
+
+ if (mType == EbtInt)
+ {
+ TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
+ mInitValue = EvaluateIntConstant(initNode);
+ mCurrentValue = mInitValue;
+ mIncrementValue = GetLoopIntIncrement(node);
+
+ TIntermBinary* binOp = node->getCondition()->getAsBinaryNode();
+ mStopValue = EvaluateIntConstant(
+ binOp->getRight()->getAsConstantUnion());
+ mOp = binOp->getOp();
+ }
+}
+
+bool TLoopIndexInfo::satisfiesLoopCondition() const
+{
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (mOp)
+ {
+ case EOpEqual:
+ return (mCurrentValue == mStopValue);
+ case EOpNotEqual:
+ return (mCurrentValue != mStopValue);
+ case EOpLessThan:
+ return (mCurrentValue < mStopValue);
+ case EOpGreaterThan:
+ return (mCurrentValue > mStopValue);
+ case EOpLessThanEqual:
+ return (mCurrentValue <= mStopValue);
+ case EOpGreaterThanEqual:
+ return (mCurrentValue >= mStopValue);
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+TLoopInfo::TLoopInfo()
+ : loop(NULL)
+{
+}
+
+TLoopInfo::TLoopInfo(TIntermLoop *node)
+ : loop(node)
+{
+ index.fillInfo(node);
+}
+
+TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol)
+{
+ if (!symbol)
+ return NULL;
+ for (iterator iter = begin(); iter != end(); ++iter)
+ {
+ if (iter->index.getId() == symbol->getId())
+ return iter->loop;
+ }
+ return NULL;
+}
+
+TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol)
+{
+ if (!symbol)
+ return NULL;
+ for (iterator iter = begin(); iter != end(); ++iter)
+ {
+ if (iter->index.getId() == symbol->getId())
+ return &(iter->index);
+ }
+ return NULL;
+}
+
+void TLoopStack::step()
+{
+ ASSERT(!empty());
+ rbegin()->index.step();
+}
+
+bool TLoopStack::satisfiesLoopCondition()
+{
+ ASSERT(!empty());
+ return rbegin()->index.satisfiesLoopCondition();
+}
+
+bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol)
+{
+ TIntermLoop *loop = findLoop(symbol);
+ return loop && loop->getUnrollFlag();
+}
+
+int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol)
+{
+ TLoopIndexInfo *info = getIndexInfo(symbol);
+ ASSERT(info);
+ return info->getCurrentValue();
+}
+
+void TLoopStack::push(TIntermLoop *loop)
+{
+ TLoopInfo info(loop);
+ push_back(info);
+}
+
+void TLoopStack::pop()
+{
+ pop_back();
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/LoopInfo.h b/chromium/third_party/angle/src/compiler/translator/LoopInfo.h
new file mode 100644
index 00000000000..5a140c339e9
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/LoopInfo.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATOR_LOOP_INFO_H_
+#define COMPILER_TRANSLATOR_LOOP_INFO_H_
+
+#include "compiler/translator/intermediate.h"
+
+class TLoopIndexInfo
+{
+ public:
+ TLoopIndexInfo();
+
+ // If type is EbtInt, fill all fields of the structure with info
+ // extracted from a loop node.
+ // If type is not EbtInt, only fill id and type.
+ void fillInfo(TIntermLoop *node);
+
+ int getId() const { return mId; }
+ void setId(int id) { mId = id; }
+ TBasicType getType() const { return mType; }
+ void setType(TBasicType type) { mType = type; }
+ int getCurrentValue() const { return mCurrentValue; }
+
+ void step() { mCurrentValue += mIncrementValue; }
+
+ // Check if the current value satisfies the loop condition.
+ bool satisfiesLoopCondition() const;
+
+ private:
+ int mId;
+ TBasicType mType; // Either EbtInt or EbtFloat
+
+ // Below fields are only valid if the index's type is int.
+ int mInitValue;
+ int mStopValue;
+ int mIncrementValue;
+ TOperator mOp;
+ int mCurrentValue;
+};
+
+struct TLoopInfo
+{
+ TLoopIndexInfo index;
+ TIntermLoop *loop;
+
+ TLoopInfo();
+ TLoopInfo(TIntermLoop *node);
+};
+
+class TLoopStack : public TVector<TLoopInfo>
+{
+ public:
+ // Search loop stack for a loop whose index matches the input symbol.
+ TIntermLoop *findLoop(TIntermSymbol *symbol);
+
+ // Find the loop index info in the loop stack by the input symbol.
+ TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol);
+
+ // Update the currentValue for the next loop iteration.
+ void step();
+
+ // Return false if loop condition is no longer satisfied.
+ bool satisfiesLoopCondition();
+
+ // Check if the symbol is the index of a loop that's unrolled.
+ bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol);
+
+ // Return the current value of a given loop index symbol.
+ int getLoopIndexValue(TIntermSymbol *symbol);
+
+ void push(TIntermLoop *info);
+ void pop();
+};
+
+#endif // COMPILER_TRANSLATOR_LOOP_INDEX_H_
+
diff --git a/chromium/third_party/angle/src/compiler/translator/MMap.h b/chromium/third_party/angle/src/compiler/translator/MMap.h
new file mode 100644
index 00000000000..a308671514c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/MMap.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _MMAP_INCLUDED_
+#define _MMAP_INCLUDED_
+
+//
+// Encapsulate memory mapped files
+//
+
+class TMMap {
+public:
+ TMMap(const char* fileName) :
+ fSize(-1), // -1 is the error value returned by GetFileSize()
+ fp(NULL),
+ fBuff(0) // 0 is the error value returned by MapViewOfFile()
+ {
+ if ((fp = fopen(fileName, "r")) == NULL)
+ return;
+ char c = getc(fp);
+ fSize = 0;
+ while (c != EOF) {
+ fSize++;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ fSize++;
+ rewind(fp);
+ fBuff = (char*)malloc(sizeof(char) * fSize);
+ int count = 0;
+ c = getc(fp);
+ while (c != EOF) {
+ fBuff[count++] = c;
+ c = getc(fp);
+ }
+ fBuff[count++] = c;
+ }
+
+ char* getData() { return fBuff; }
+ int getSize() { return fSize; }
+
+ ~TMMap() {
+ if (fp != NULL)
+ fclose(fp);
+ }
+
+private:
+ int fSize; // size of file to map in
+ FILE *fp;
+ char* fBuff; // the actual data;
+};
+
+#endif // _MMAP_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/NodeSearch.h b/chromium/third_party/angle/src/compiler/translator/NodeSearch.h
new file mode 100644
index 00000000000..b58c7ec6894
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/NodeSearch.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NodeSearch.h: Utilities for searching translator node graphs
+//
+
+#ifndef TRANSLATOR_NODESEARCH_H_
+#define TRANSLATOR_NODESEARCH_H_
+
+#include "compiler/translator/intermediate.h"
+
+namespace sh
+{
+
+template <class Parent>
+class NodeSearchTraverser : public TIntermTraverser
+{
+ public:
+ NodeSearchTraverser()
+ : mFound(false)
+ {}
+
+ bool found() const { return mFound; }
+
+ static bool search(TIntermNode *node)
+ {
+ Parent searchTraverser;
+ node->traverse(&searchTraverser);
+ return searchTraverser.found();
+ }
+
+ protected:
+ bool mFound;
+};
+
+class FindDiscard : public NodeSearchTraverser<FindDiscard>
+{
+ public:
+ virtual bool visitBranch(Visit visit, TIntermBranch *node)
+ {
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ mFound = true;
+ break;
+
+ default: break;
+ }
+
+ return !mFound;
+ }
+};
+
+class FindSideEffectRewriting : public NodeSearchTraverser<FindSideEffectRewriting>
+{
+ public:
+ virtual bool visitBinary(Visit visit, TIntermBinary *node)
+ {
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ case EOpLogicalAnd:
+ if (node->getRight()->hasSideEffects())
+ {
+ mFound = true;
+ }
+ break;
+
+ default: break;
+ }
+
+ return !mFound;
+ }
+};
+
+}
+
+#endif // TRANSLATOR_NODESEARCH_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp
new file mode 100644
index 00000000000..65635af1fff
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp
@@ -0,0 +1,27 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputESSL.h"
+
+TOutputESSL::TOutputESSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion)
+ : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion)
+{
+}
+
+bool TOutputESSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase& out = objSink();
+ out << getPrecisionString(precision);
+ return true;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputESSL.h b/chromium/third_party/angle/src/compiler/translator/OutputESSL.h
new file mode 100644
index 00000000000..8a567fb8aa2
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputESSL.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
+
+#include "compiler/translator/OutputGLSLBase.h"
+
+class TOutputESSL : public TOutputGLSLBase
+{
+public:
+ TOutputESSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision precision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp
new file mode 100644
index 00000000000..eb7cbb4ae86
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputGLSL.h"
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion)
+ : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion)
+{
+}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (node->getSymbol() == "gl_FragDepthEXT")
+ {
+ out << "gl_FragDepth";
+ }
+ else
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ }
+}
+
+TString TOutputGLSL::translateTextureFunction(TString& name)
+{
+ static const char *simpleRename[] = {
+ "texture2DLodEXT", "texture2DLod",
+ "texture2DProjLodEXT", "texture2DProjLod",
+ "textureCubeLodEXT", "textureCubeLod",
+ "texture2DGradEXT", "texture2DGradARB",
+ "texture2DProjGradEXT", "texture2DProjGradARB",
+ "textureCubeGradEXT", "textureCubeGradARB",
+ NULL, NULL
+ };
+
+ for (int i = 0; simpleRename[i] != NULL; i += 2) {
+ if (name == simpleRename[i]) {
+ return simpleRename[i+1];
+ }
+ }
+
+ return name;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h
new file mode 100644
index 00000000000..bceebe397d7
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+
+#include "compiler/translator/OutputGLSLBase.h"
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+public:
+ TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision);
+ virtual void visitSymbol(TIntermSymbol* node);
+ virtual TString translateTextureFunction(TString& name);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp
new file mode 100644
index 00000000000..6995594e760
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -0,0 +1,1080 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputGLSLBase.h"
+#include "compiler/translator/compilerdebug.h"
+
+#include <cfloat>
+
+namespace
+{
+TString arrayBrackets(const TType &type)
+{
+ ASSERT(type.isArray());
+ TInfoSinkBase out;
+ out << "[" << type.getArraySize() << "]";
+ return TString(out.c_str());
+}
+
+bool isSingleStatement(TIntermNode *node)
+{
+ if (const TIntermAggregate *aggregate = node->getAsAggregate())
+ {
+ return (aggregate->getOp() != EOpFunction) &&
+ (aggregate->getOp() != EOpSequence);
+ }
+ else if (const TIntermSelection *selection = node->getAsSelectionNode())
+ {
+ // Ternary operators are usually part of an assignment operator.
+ // This handles those rare cases in which they are all by themselves.
+ return selection->usesTernaryOperator();
+ }
+ else if (node->getAsLoopNode())
+ {
+ return false;
+ }
+ return true;
+}
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TIntermTraverser(true, true, true),
+ mObjSink(objSink),
+ mDeclaringVariables(false),
+ mClampingStrategy(clampingStrategy),
+ mHashFunction(hashFunction),
+ mNameMap(nameMap),
+ mSymbolTable(symbolTable),
+ mShaderVersion(shaderVersion)
+{
+ // Set up global scope.
+ mDeclaredStructs.push_back(ScopedDeclaredStructs());
+}
+
+void TOutputGLSLBase::writeTriplet(
+ Visit visit, const char *preStr, const char *inStr, const char *postStr)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit && preStr)
+ out << preStr;
+ else if (visit == InVisit && inStr)
+ out << inStr;
+ else if (visit == PostVisit && postStr)
+ out << postStr;
+}
+
+void TOutputGLSLBase::writeBuiltInFunctionTriplet(
+ Visit visit, const char *preStr, bool useEmulatedFunction)
+{
+ TString preString = useEmulatedFunction ?
+ BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
+ writeTriplet(visit, preString.c_str(), ", ", ")");
+}
+
+void TOutputGLSLBase::writeVariableType(const TType &type)
+{
+ TInfoSinkBase &out = objSink();
+ TQualifier qualifier = type.getQualifier();
+ // TODO(alokp): Validate qualifier for variable declarations.
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ out << type.getQualifierString() << " ";
+ // Declare the struct if we have not done so already.
+ if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
+ {
+ declareStruct(type.getStruct());
+ mDeclaredStructs[mDeclaredStructs.size() - 1].push_back(type.getStruct());
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
+{
+ TInfoSinkBase &out = objSink();
+ for (TIntermSequence::const_iterator iter = args.begin();
+ iter != args.end(); ++iter)
+ {
+ const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
+ ASSERT(arg != NULL);
+
+ const TType &type = arg->getType();
+ writeVariableType(type);
+
+ const TString &name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << hashName(name);
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ // Put a comma if this is not the last argument.
+ if (iter != args.end() - 1)
+ out << ", ";
+ }
+}
+
+const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
+ const TType &type, const ConstantUnion *pConstUnion)
+{
+ TInfoSinkBase &out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ const TStructure *structure = type.getStruct();
+ out << hashName(structure->name()) << "(";
+
+ const TFieldList &fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TType *fieldType = fields[i]->type();
+ ASSERT(fieldType != NULL);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != fields.size() - 1)
+ out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType)
+ out << getTypeName(type) << "(";
+ for (size_t i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat:
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
+ break;
+ case EbtInt:
+ out << pConstUnion->getIConst();
+ break;
+ case EbtBool:
+ out << pConstUnion->getBConst();
+ break;
+ default: UNREACHABLE();
+ }
+ if (i != size - 1)
+ out << ", ";
+ }
+ if (writeType)
+ out << ")";
+ }
+ return pConstUnion;
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
+ out << mLoopUnrollStack.getLoopIndexValue(node);
+ else
+ out << hashVariableName(node->getSymbol());
+
+ if (mDeclaringVariables && node->getType().isArray())
+ out << arrayBrackets(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ switch (node->getOp())
+ {
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpAssign:
+ writeTriplet(visit, "(", " = ", ")");
+ break;
+ case EOpAddAssign:
+ writeTriplet(visit, "(", " += ", ")");
+ break;
+ case EOpSubAssign:
+ writeTriplet(visit, "(", " -= ", ")");
+ break;
+ case EOpDivAssign:
+ writeTriplet(visit, "(", " /= ", ")");
+ break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ writeTriplet(visit, NULL, "[", "]");
+ break;
+ case EOpIndexIndirect:
+ if (node->getAddIndexClamp())
+ {
+ if (visit == InVisit)
+ {
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "[int(clamp(float(";
+ else
+ out << "[webgl_int_clamp(";
+ }
+ else if (visit == PostVisit)
+ {
+ int maxSize;
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (left->isArray())
+ {
+ // The shader will fail validation if the array length is not > 0.
+ maxSize = leftType.getArraySize() - 1;
+ }
+ else
+ {
+ maxSize = leftType.getNominalSize() - 1;
+ }
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ out << "), 0.0, float(" << maxSize << ")))]";
+ else
+ out << ", 0, " << maxSize << ")]";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, NULL, "[", "]");
+ }
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ // Here we are writing out "foo.bar", where "foo" is struct
+ // and "bar" is field. In AST, it is represented as a binary
+ // node, where left child represents "foo" and right child "bar".
+ // The node itself represents ".". The struct field "bar" is
+ // actually stored as an index into TStructure::fields.
+ out << ".";
+ const TStructure *structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = structure->fields()[index->getIConst(0)];
+
+ TString fieldName = field->name();
+ if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence &sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+ {
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const ConstantUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0:
+ out << "x";
+ break;
+ case 1:
+ out << "y";
+ break;
+ case 2:
+ out << "z";
+ break;
+ case 3:
+ out << "w";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd:
+ writeTriplet(visit, "(", " + ", ")");
+ break;
+ case EOpSub:
+ writeTriplet(visit, "(", " - ", ")");
+ break;
+ case EOpMul:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+ case EOpDiv:
+ writeTriplet(visit, "(", " / ", ")");
+ break;
+ case EOpMod:
+ UNIMPLEMENTED();
+ break;
+ case EOpEqual:
+ writeTriplet(visit, "(", " == ", ")");
+ break;
+ case EOpNotEqual:
+ writeTriplet(visit, "(", " != ", ")");
+ break;
+ case EOpLessThan:
+ writeTriplet(visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ writeTriplet(visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ writeTriplet(visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ writeTriplet(visit, "(", " >= ", ")");
+ break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr:
+ writeTriplet(visit, "(", " || ", ")");
+ break;
+ case EOpLogicalXor:
+ writeTriplet(visit, "(", " ^^ ", ")");
+ break;
+ case EOpLogicalAnd:
+ writeTriplet(visit, "(", " && ", ")");
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
+{
+ TString preString;
+ TString postString = ")";
+
+ switch (node->getOp())
+ {
+ case EOpNegative: preString = "(-"; break;
+ case EOpVectorLogicalNot: preString = "not("; break;
+ case EOpLogicalNot: preString = "(!"; break;
+
+ case EOpPostIncrement: preString = "("; postString = "++)"; break;
+ case EOpPostDecrement: preString = "("; postString = "--)"; break;
+ case EOpPreIncrement: preString = "(++"; break;
+ case EOpPreDecrement: preString = "(--"; break;
+
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1:
+ preString = "bool(";
+ break;
+ case 2:
+ preString = "bvec2(";
+ break;
+ case 3:
+ preString = "bvec3(";
+ break;
+ case 4:
+ preString = "bvec4(";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1:
+ preString = "float(";
+ break;
+ case 2:
+ preString = "vec2(";
+ break;
+ case 3:
+ preString = "vec3(";
+ break;
+ case 4:
+ preString = "vec4(";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1:
+ preString = "int(";
+ break;
+ case 2:
+ preString = "ivec2(";
+ break;
+ case 3:
+ preString = "ivec3(";
+ break;
+ case 4:
+ preString = "ivec4(";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+
+ case EOpRadians:
+ preString = "radians(";
+ break;
+ case EOpDegrees:
+ preString = "degrees(";
+ break;
+ case EOpSin:
+ preString = "sin(";
+ break;
+ case EOpCos:
+ preString = "cos(";
+ break;
+ case EOpTan:
+ preString = "tan(";
+ break;
+ case EOpAsin:
+ preString = "asin(";
+ break;
+ case EOpAcos:
+ preString = "acos(";
+ break;
+ case EOpAtan:
+ preString = "atan(";
+ break;
+
+ case EOpExp:
+ preString = "exp(";
+ break;
+ case EOpLog:
+ preString = "log(";
+ break;
+ case EOpExp2:
+ preString = "exp2(";
+ break;
+ case EOpLog2:
+ preString = "log2(";
+ break;
+ case EOpSqrt:
+ preString = "sqrt(";
+ break;
+ case EOpInverseSqrt:
+ preString = "inversesqrt(";
+ break;
+
+ case EOpAbs:
+ preString = "abs(";
+ break;
+ case EOpSign:
+ preString = "sign(";
+ break;
+ case EOpFloor:
+ preString = "floor(";
+ break;
+ case EOpCeil:
+ preString = "ceil(";
+ break;
+ case EOpFract:
+ preString = "fract(";
+ break;
+
+ case EOpLength:
+ preString = "length(";
+ break;
+ case EOpNormalize:
+ preString = "normalize(";
+ break;
+
+ case EOpDFdx:
+ preString = "dFdx(";
+ break;
+ case EOpDFdy:
+ preString = "dFdy(";
+ break;
+ case EOpFwidth:
+ preString = "fwidth(";
+ break;
+
+ case EOpAny:
+ preString = "any(";
+ break;
+ case EOpAll:
+ preString = "all(";
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ if (visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+
+ return true;
+}
+
+bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ if (node->usesTernaryOperator())
+ {
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueBlock()->traverse(this);
+ out << ") : (";
+ node->getFalseBlock()->traverse(this);
+ out << "))";
+ }
+ else
+ {
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ incrementDepth(node);
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase &out = objSink();
+ TString preString;
+ bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ // Scope the sequences except when at the global scope.
+ if (depth > 0)
+ {
+ out << "{\n";
+ pushDeclaredStructsScope();
+ }
+
+ incrementDepth(node);
+ for (TIntermSequence::const_iterator iter = node->getSequence().begin();
+ iter != node->getSequence().end(); ++iter)
+ {
+ TIntermNode *node = *iter;
+ ASSERT(node != NULL);
+ node->traverse(this);
+
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ decrementDepth();
+
+ // Scope the sequences except when at the global scope.
+ if (depth > 0)
+ {
+ popDeclaredStructsScope();
+ out << "}\n";
+ }
+ visitChildren = false;
+ break;
+ case EOpPrototype:
+ // Function declaration.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << hashName(node->getName());
+
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+
+ visitChildren = false;
+ break;
+ case EOpFunction: {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << hashFunctionName(node->getName());
+
+ incrementDepth(node);
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence &sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate *params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate *body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ visitCodeBlock(body);
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpFunctionCall:
+ // Function call.
+ if (visit == PreVisit)
+ out << hashFunctionName(node->getName()) << "(";
+ else if (visit == InVisit)
+ out << ", ";
+ else
+ out << ")";
+ break;
+ case EOpParameters:
+ // Function parameters.
+ ASSERT(visit == PreVisit);
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+ visitChildren = false;
+ break;
+ case EOpDeclaration:
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence &sequence = node->getSequence();
+ const TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpConstructFloat:
+ writeTriplet(visit, "float(", NULL, ")");
+ break;
+ case EOpConstructVec2:
+ writeBuiltInFunctionTriplet(visit, "vec2(", false);
+ break;
+ case EOpConstructVec3:
+ writeBuiltInFunctionTriplet(visit, "vec3(", false);
+ break;
+ case EOpConstructVec4:
+ writeBuiltInFunctionTriplet(visit, "vec4(", false);
+ break;
+ case EOpConstructBool:
+ writeTriplet(visit, "bool(", NULL, ")");
+ break;
+ case EOpConstructBVec2:
+ writeBuiltInFunctionTriplet(visit, "bvec2(", false);
+ break;
+ case EOpConstructBVec3:
+ writeBuiltInFunctionTriplet(visit, "bvec3(", false);
+ break;
+ case EOpConstructBVec4:
+ writeBuiltInFunctionTriplet(visit, "bvec4(", false);
+ break;
+ case EOpConstructInt:
+ writeTriplet(visit, "int(", NULL, ")");
+ break;
+ case EOpConstructIVec2:
+ writeBuiltInFunctionTriplet(visit, "ivec2(", false);
+ break;
+ case EOpConstructIVec3:
+ writeBuiltInFunctionTriplet(visit, "ivec3(", false);
+ break;
+ case EOpConstructIVec4:
+ writeBuiltInFunctionTriplet(visit, "ivec4(", false);
+ break;
+ case EOpConstructMat2:
+ writeBuiltInFunctionTriplet(visit, "mat2(", false);
+ break;
+ case EOpConstructMat3:
+ writeBuiltInFunctionTriplet(visit, "mat3(", false);
+ break;
+ case EOpConstructMat4:
+ writeBuiltInFunctionTriplet(visit, "mat4(", false);
+ break;
+ case EOpConstructStruct:
+ if (visit == PreVisit)
+ {
+ const TType &type = node->getType();
+ ASSERT(type.getBasicType() == EbtStruct);
+ out << hashName(type.getStruct()->name()) << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+
+ case EOpLessThan:
+ writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
+ break;
+ case EOpGreaterThan:
+ writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
+ break;
+ case EOpLessThanEqual:
+ writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
+ break;
+ case EOpGreaterThanEqual:
+ writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
+ break;
+ case EOpVectorEqual:
+ writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
+ break;
+ case EOpVectorNotEqual:
+ writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
+ break;
+ case EOpComma:
+ writeTriplet(visit, NULL, ", ", NULL);
+ break;
+
+ case EOpMod:
+ writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
+ break;
+ case EOpPow:
+ writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
+ break;
+ case EOpAtan:
+ writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
+ break;
+ case EOpMin:
+ writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
+ break;
+ case EOpMax:
+ writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
+ break;
+ case EOpClamp:
+ writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
+ break;
+ case EOpMix:
+ writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
+ break;
+ case EOpStep:
+ writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
+ break;
+ case EOpSmoothStep:
+ writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
+ break;
+ case EOpDistance:
+ writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
+ break;
+ case EOpDot:
+ writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
+ break;
+ case EOpCross:
+ writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
+ break;
+ case EOpFaceForward:
+ writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
+ break;
+ case EOpReflect:
+ writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
+ break;
+ case EOpRefract:
+ writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
+ break;
+ case EOpMul:
+ writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
+{
+ TInfoSinkBase &out = objSink();
+
+ incrementDepth(node);
+ // Loop header.
+ TLoopType loopType = node->getType();
+ if (loopType == ELoopFor) // for loop
+ {
+ if (!node->getUnrollFlag())
+ {
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
+ }
+ else
+ {
+ // Need to put a one-iteration loop here to handle break.
+ TIntermSequence &declSeq =
+ node->getInit()->getAsAggregate()->getSequence();
+ TIntermSymbol *indexSymbol =
+ declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+ TString name = hashVariableName(indexSymbol->getSymbol());
+ out << "for (int " << name << " = 0; "
+ << name << " < 1; "
+ << "++" << name << ")\n";
+ }
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ")\n";
+ }
+ else // do-while loop
+ {
+ ASSERT(loopType == ELoopDoWhile);
+ out << "do\n";
+ }
+
+ // Loop body.
+ if (node->getUnrollFlag())
+ {
+ out << "{\n";
+ mLoopUnrollStack.push(node);
+ while (mLoopUnrollStack.satisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnrollStack.step();
+ }
+ mLoopUnrollStack.pop();
+ out << "}\n";
+ }
+ else
+ {
+ visitCodeBlock(node->getBody());
+ }
+
+ // Loop footer.
+ if (loopType == ELoopDoWhile) // do-while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+ decrementDepth();
+
+ // No need to visit children. They have been already processed in
+ // this function.
+ return false;
+}
+
+bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
+{
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ writeTriplet(visit, "discard", NULL, NULL);
+ break;
+ case EOpBreak:
+ writeTriplet(visit, "break", NULL, NULL);
+ break;
+ case EOpContinue:
+ writeTriplet(visit, "continue", NULL, NULL);
+ break;
+ case EOpReturn:
+ writeTriplet(visit, "return ", NULL, NULL);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
+{
+ TInfoSinkBase &out = objSink();
+ if (node != NULL)
+ {
+ node->traverse(this);
+ // Single statements not part of a sequence need to be terminated
+ // with semi-colon.
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ else
+ {
+ out << "{\n}\n"; // Empty code block.
+ }
+}
+
+TString TOutputGLSLBase::getTypeName(const TType &type)
+{
+ TInfoSinkBase out;
+ if (type.isMatrix())
+ {
+ out << "mat";
+ out << type.getNominalSize();
+ }
+ else if (type.isVector())
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ out << "vec";
+ break;
+ case EbtInt:
+ out << "ivec";
+ break;
+ case EbtBool:
+ out << "bvec";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ out << type.getNominalSize();
+ }
+ else
+ {
+ if (type.getBasicType() == EbtStruct)
+ out << hashName(type.getStruct()->name());
+ else
+ out << type.getBasicString();
+ }
+ return TString(out.c_str());
+}
+
+TString TOutputGLSLBase::hashName(const TString &name)
+{
+ if (mHashFunction == NULL || name.empty())
+ return name;
+ NameMap::const_iterator it = mNameMap.find(name.c_str());
+ if (it != mNameMap.end())
+ return it->second.c_str();
+ TString hashedName = TIntermTraverser::hash(name, mHashFunction);
+ mNameMap[name.c_str()] = hashedName.c_str();
+ return hashedName;
+}
+
+TString TOutputGLSLBase::hashVariableName(const TString &name)
+{
+ if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
+ return name;
+ return hashName(name);
+}
+
+TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
+{
+ TString name = TFunction::unmangleName(mangled_name);
+ if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
+ return translateTextureFunction(name);
+ return hashName(name);
+}
+
+bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
+{
+ ASSERT(structure);
+ ASSERT(mDeclaredStructs.size() > 0);
+ for (size_t ii = mDeclaredStructs.size(); ii > 0; --ii)
+ {
+ const ScopedDeclaredStructs &scope = mDeclaredStructs[ii - 1];
+ for (size_t jj = 0; jj < scope.size(); ++jj)
+ {
+ if (scope[jj]->equals(*structure))
+ return true;
+ }
+ }
+ return false;
+}
+
+void TOutputGLSLBase::declareStruct(const TStructure *structure)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "struct " << hashName(structure->name()) << "{\n";
+ const TFieldList &fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TField *field = fields[i];
+ if (writeVariablePrecision(field->type()->getPrecision()))
+ out << " ";
+ out << getTypeName(*field->type()) << " " << hashName(field->name());
+ if (field->type()->isArray())
+ out << arrayBrackets(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+}
+
+void TOutputGLSLBase::pushDeclaredStructsScope()
+{
+ mDeclaredStructs.push_back(ScopedDeclaredStructs());
+}
+
+void TOutputGLSLBase::popDeclaredStructsScope()
+{
+ // We should never pop the global scope.
+ ASSERT(mDeclaredStructs.size() >= 2);
+ mDeclaredStructs.pop_back();
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h
new file mode 100644
index 00000000000..ae40f85e0d5
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h
@@ -0,0 +1,91 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+
+#include <vector>
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/LoopInfo.h"
+#include "compiler/translator/ParseContext.h"
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+ public:
+ TOutputGLSLBase(TInfoSinkBase &objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap &nameMap,
+ TSymbolTable& symbolTable,
+ int shaderVersion);
+
+ protected:
+ TInfoSinkBase &objSink() { return mObjSink; }
+ void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
+ void writeVariableType(const TType &type);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TIntermSequence &args);
+ const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *pConstUnion);
+ TString getTypeName(const TType &type);
+
+ virtual void visitSymbol(TIntermSymbol *node);
+ virtual void visitConstantUnion(TIntermConstantUnion *node);
+ virtual bool visitBinary(Visit visit, TIntermBinary *node);
+ virtual bool visitUnary(Visit visit, TIntermUnary *node);
+ virtual bool visitSelection(Visit visit, TIntermSelection *node);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate *node);
+ virtual bool visitLoop(Visit visit, TIntermLoop *node);
+ virtual bool visitBranch(Visit visit, TIntermBranch *node);
+
+ void visitCodeBlock(TIntermNode *node);
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ TString hashName(const TString &name);
+ // Same as hashName(), but without hashing built-in variables.
+ TString hashVariableName(const TString &name);
+ // Same as hashName(), but without hashing built-in functions.
+ TString hashFunctionName(const TString &mangled_name);
+ // Used to translate function names for differences between ESSL and GLSL
+ virtual TString translateTextureFunction(TString &name) { return name; }
+
+ private:
+ bool structDeclared(const TStructure *structure) const;
+ void declareStruct(const TStructure *structure);
+ void pushDeclaredStructsScope();
+ void popDeclaredStructsScope();
+
+ void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction);
+
+ TInfoSinkBase &mObjSink;
+ bool mDeclaringVariables;
+
+ // Structs are declared as the tree is traversed. This list contains all
+ // the structs already declared within a scope. It is maintained so that
+ // a struct is declared only once within a scope.
+ typedef std::vector<TStructure *> ScopedDeclaredStructs;
+ // This vector contains all the structs from the global scope to the
+ // current scope. When the traverser exits a scope, the scope is discarded.
+ typedef std::vector<ScopedDeclaredStructs> DeclaredStructs;
+ DeclaredStructs mDeclaredStructs;
+
+ // Stack of loops that need to be unrolled.
+ TLoopStack mLoopUnrollStack;
+
+ ShArrayIndexClampingStrategy mClampingStrategy;
+
+ // name hashing.
+ ShHashFunction64 mHashFunction;
+
+ NameMap &mNameMap;
+
+ TSymbolTable &mSymbolTable;
+
+ const int mShaderVersion;
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp
new file mode 100644
index 00000000000..5520c861b4d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp
@@ -0,0 +1,4184 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/OutputHLSL.h"
+
+#include "common/angleutils.h"
+#include "common/utilities.h"
+#include "common/blocklayout.h"
+#include "compiler/translator/compilerdebug.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/DetectDiscontinuity.h"
+#include "compiler/translator/SearchSymbol.h"
+#include "compiler/translator/UnfoldShortCircuit.h"
+#include "compiler/translator/FlagStd140Structs.h"
+#include "compiler/translator/NodeSearch.h"
+#include "compiler/translator/RewriteElseBlocks.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <stdio.h>
+
+namespace sh
+{
+
+TString OutputHLSL::TextureFunction::name() const
+{
+ TString name = "gl_texture";
+
+ if (IsSampler2D(sampler))
+ {
+ name += "2D";
+ }
+ else if (IsSampler3D(sampler))
+ {
+ name += "3D";
+ }
+ else if (IsSamplerCube(sampler))
+ {
+ name += "Cube";
+ }
+ else UNREACHABLE();
+
+ if (proj)
+ {
+ name += "Proj";
+ }
+
+ if (offset)
+ {
+ name += "Offset";
+ }
+
+ switch(method)
+ {
+ case IMPLICIT: break;
+ case BIAS: break; // Extra parameter makes the signature unique
+ case LOD: name += "Lod"; break;
+ case LOD0: name += "Lod0"; break;
+ case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique
+ case SIZE: name += "Size"; break;
+ case FETCH: name += "Fetch"; break;
+ case GRAD: name += "Grad"; break;
+ default: UNREACHABLE();
+ }
+
+ return name + "(";
+}
+
+const char *RegisterPrefix(const TType &type)
+{
+ if (IsSampler(type.getBasicType()))
+ {
+ return "s";
+ }
+ else
+ {
+ return "c";
+ }
+}
+
+bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const
+{
+ if (sampler < rhs.sampler) return true;
+ if (sampler > rhs.sampler) return false;
+
+ if (coords < rhs.coords) return true;
+ if (coords > rhs.coords) return false;
+
+ if (!proj && rhs.proj) return true;
+ if (proj && !rhs.proj) return false;
+
+ if (!offset && rhs.offset) return true;
+ if (offset && !rhs.offset) return false;
+
+ if (method < rhs.method) return true;
+ if (method > rhs.method) return false;
+
+ return false;
+}
+
+OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
+ : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
+{
+ mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
+ mInsideFunction = false;
+
+ mUsesFragColor = false;
+ mUsesFragData = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesFragDepth = false;
+ mUsesXor = false;
+ mUsesMod1 = false;
+ mUsesMod2v = false;
+ mUsesMod2f = false;
+ mUsesMod3v = false;
+ mUsesMod3f = false;
+ mUsesMod4v = false;
+ mUsesMod4f = false;
+ mUsesFaceforward1 = false;
+ mUsesFaceforward2 = false;
+ mUsesFaceforward3 = false;
+ mUsesFaceforward4 = false;
+ mUsesAtan2_1 = false;
+ mUsesAtan2_2 = false;
+ mUsesAtan2_3 = false;
+ mUsesAtan2_4 = false;
+ mUsesDiscardRewriting = false;
+ mUsesNestedBreak = false;
+
+ mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
+
+ mUniqueIndex = 0;
+
+ mContainsLoopDiscontinuity = false;
+ mOutputLod0Function = false;
+ mInsideDiscontinuousLoop = false;
+ mNestedLoopDepth = 0;
+
+ mExcessiveLoopIndex = NULL;
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ if (mContext.shaderType == SH_FRAGMENT_SHADER)
+ {
+ mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
+ }
+ else
+ {
+ mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust
+ }
+ }
+ else
+ {
+ mUniformRegister = 0;
+ }
+
+ mSamplerRegister = 0;
+ mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants
+ mPaddingCounter = 0;
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ delete mUnfoldShortCircuit;
+}
+
+void OutputHLSL::output()
+{
+ mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
+ const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot);
+ makeFlaggedStructMaps(flaggedStructs);
+
+ // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
+ // use a vertex attribute as a condition, and some related computation in the else block.
+ if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER)
+ {
+ RewriteElseBlocks(mContext.treeRoot);
+ }
+
+ mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
+ header();
+
+ mContext.infoSink().obj << mHeader.c_str();
+ mContext.infoSink().obj << mBody.c_str();
+}
+
+void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
+{
+ for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
+ {
+ TIntermTyped *flaggedNode = flaggedStructs[structIndex];
+
+ // This will mark the necessary block elements as referenced
+ flaggedNode->traverse(this);
+ TString structName(mBody.c_str());
+ mBody.erase();
+
+ mFlaggedStructOriginalNames[flaggedNode] = structName;
+
+ for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
+ {
+ structName.erase(pos, 1);
+ }
+
+ mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
+ }
+}
+
+TInfoSinkBase &OutputHLSL::getBodyStream()
+{
+ return mBody;
+}
+
+const std::vector<gl::Uniform> &OutputHLSL::getUniforms()
+{
+ return mActiveUniforms;
+}
+
+const std::vector<gl::InterfaceBlock> &OutputHLSL::getInterfaceBlocks() const
+{
+ return mActiveInterfaceBlocks;
+}
+
+const std::vector<gl::Attribute> &OutputHLSL::getOutputVariables() const
+{
+ return mActiveOutputVariables;
+}
+
+const std::vector<gl::Attribute> &OutputHLSL::getAttributes() const
+{
+ return mActiveAttributes;
+}
+
+const std::vector<gl::Varying> &OutputHLSL::getVaryings() const
+{
+ return mActiveVaryings;
+}
+
+int OutputHLSL::vectorSize(const TType &type) const
+{
+ int elementSize = type.isMatrix() ? type.getCols() : 1;
+ int arraySize = type.isArray() ? type.getArraySize() : 1;
+
+ return elementSize * arraySize;
+}
+
+TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field)
+{
+ if (interfaceBlock.hasInstanceName())
+ {
+ return interfaceBlock.name() + "." + field.name();
+ }
+ else
+ {
+ return field.name();
+ }
+}
+
+TString OutputHLSL::decoratePrivate(const TString &privateText)
+{
+ return "dx_" + privateText;
+}
+
+TString OutputHLSL::interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlock)
+{
+ return decoratePrivate(interfaceBlock.name()) + "_type";
+}
+
+TString OutputHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
+{
+ if (!interfaceBlock.hasInstanceName())
+ {
+ return "";
+ }
+ else if (interfaceBlock.isArray())
+ {
+ return decoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
+ }
+ else
+ {
+ return decorate(interfaceBlock.instanceName());
+ }
+}
+
+TString OutputHLSL::interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
+{
+ const TType &fieldType = *field.type();
+ const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
+ ASSERT(matrixPacking != EmpUnspecified);
+
+ if (fieldType.isMatrix())
+ {
+ // Use HLSL row-major packing for GLSL column-major matrices
+ const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
+ return matrixPackString + " " + typeString(fieldType);
+ }
+ else if (fieldType.getStruct())
+ {
+ // Use HLSL row-major packing for GLSL column-major matrices
+ return structureTypeName(*fieldType.getStruct(), matrixPacking == EmpColumnMajor, blockStorage == EbsStd140);
+ }
+ else
+ {
+ return typeString(fieldType);
+ }
+}
+
+TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
+{
+ TString hlsl;
+
+ int elementIndex = 0;
+
+ for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
+ {
+ const TField &field = *interfaceBlock.fields()[typeIndex];
+ const TType &fieldType = *field.type();
+
+ if (blockStorage == EbsStd140)
+ {
+ // 2 and 3 component vector types in some cases need pre-padding
+ hlsl += std140PrePaddingString(fieldType, &elementIndex);
+ }
+
+ hlsl += " " + interfaceBlockFieldTypeString(field, blockStorage) +
+ " " + decorate(field.name()) + arrayString(fieldType) + ";\n";
+
+ // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
+ if (blockStorage == EbsStd140)
+ {
+ const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
+ hlsl += std140PostPaddingString(fieldType, useHLSLRowMajorPacking);
+ }
+ }
+
+ return hlsl;
+}
+
+TString OutputHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
+{
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+
+ return "struct " + interfaceBlockStructNameString(interfaceBlock) + "\n"
+ "{\n" +
+ interfaceBlockFieldString(interfaceBlock, blockStorage) +
+ "};\n\n";
+}
+
+TString OutputHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
+{
+ const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? decorate(str(arrayIndex)) : "");
+ const TString &blockName = interfaceBlock.name() + arrayIndexString;
+ TString hlsl;
+
+ hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
+ "{\n";
+
+ if (interfaceBlock.hasInstanceName())
+ {
+ hlsl += " " + interfaceBlockStructNameString(interfaceBlock) + " " + interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
+ }
+ else
+ {
+ const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
+ hlsl += interfaceBlockFieldString(interfaceBlock, blockStorage);
+ }
+
+ hlsl += "};\n\n";
+
+ return hlsl;
+}
+
+TString OutputHLSL::std140PrePaddingString(const TType &type, int *elementIndex)
+{
+ if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
+ {
+ // no padding needed, HLSL will align the field to a new register
+ *elementIndex = 0;
+ return "";
+ }
+
+ const GLenum glType = glVariableType(type);
+ const int numComponents = gl::UniformComponentCount(glType);
+
+ if (numComponents >= 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ *elementIndex = 0;
+ return "";
+ }
+
+ if (*elementIndex + numComponents > 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ *elementIndex = numComponents;
+ return "";
+ }
+
+ TString padding;
+
+ const int alignment = numComponents == 3 ? 4 : numComponents;
+ const int paddingOffset = (*elementIndex % alignment);
+
+ if (paddingOffset != 0)
+ {
+ // padding is neccessary
+ for (int paddingIndex = paddingOffset; paddingIndex < alignment; paddingIndex++)
+ {
+ padding += " float pad_" + str(mPaddingCounter++) + ";\n";
+ }
+
+ *elementIndex += (alignment - paddingOffset);
+ }
+
+ *elementIndex += numComponents;
+ *elementIndex %= 4;
+
+ return padding;
+}
+
+TString OutputHLSL::std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking)
+{
+ if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ return "";
+ }
+
+ int numComponents = 0;
+
+ if (type.isMatrix())
+ {
+ // This method can also be called from structureString, which does not use layout qualifiers.
+ // Thus, use the method parameter for determining the matrix packing.
+ //
+ // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
+ // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
+ //
+ const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
+ const GLenum glType = glVariableType(type);
+ numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
+ }
+ else if (type.getStruct())
+ {
+ const TString &structName = structureTypeName(*type.getStruct(), useHLSLRowMajorPacking, true);
+ numComponents = mStd140StructElementIndexes[structName];
+
+ if (numComponents == 0)
+ {
+ return "";
+ }
+ }
+ else
+ {
+ const GLenum glType = glVariableType(type);
+ numComponents = gl::UniformComponentCount(glType);
+ }
+
+ TString padding;
+ for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
+ {
+ padding += " float pad_" + str(mPaddingCounter++) + ";\n";
+ }
+ return padding;
+}
+
+// Use the same layout for packed and shared
+void setBlockLayout(gl::InterfaceBlock *interfaceBlock, gl::BlockLayoutType newLayout)
+{
+ interfaceBlock->layout = newLayout;
+ interfaceBlock->blockInfo.clear();
+
+ switch (newLayout)
+ {
+ case gl::BLOCKLAYOUT_SHARED:
+ case gl::BLOCKLAYOUT_PACKED:
+ {
+ gl::HLSLBlockEncoder hlslEncoder(&interfaceBlock->blockInfo, gl::HLSLBlockEncoder::ENCODE_PACKED);
+ hlslEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
+ interfaceBlock->dataSize = hlslEncoder.getBlockSize();
+ }
+ break;
+
+ case gl::BLOCKLAYOUT_STANDARD:
+ {
+ gl::Std140BlockEncoder stdEncoder(&interfaceBlock->blockInfo);
+ stdEncoder.encodeInterfaceBlockFields(interfaceBlock->fields);
+ interfaceBlock->dataSize = stdEncoder.getBlockSize();
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+gl::BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage)
+{
+ switch (blockStorage)
+ {
+ case EbsPacked: return gl::BLOCKLAYOUT_PACKED;
+ case EbsShared: return gl::BLOCKLAYOUT_SHARED;
+ case EbsStd140: return gl::BLOCKLAYOUT_STANDARD;
+ default: UNREACHABLE(); return gl::BLOCKLAYOUT_SHARED;
+ }
+}
+
+TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
+{
+ TString init;
+
+ TString preIndentString;
+ TString fullIndentString;
+
+ for (int spaces = 0; spaces < (indent * 4); spaces++)
+ {
+ preIndentString += ' ';
+ }
+
+ for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
+ {
+ fullIndentString += ' ';
+ }
+
+ init += preIndentString + "{\n";
+
+ const TFieldList &fields = structure.fields();
+ for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ const TField &field = *fields[fieldIndex];
+ const TString &fieldName = rhsStructName + "." + decorate(field.name());
+ const TType &fieldType = *field.type();
+
+ if (fieldType.getStruct())
+ {
+ init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
+ }
+ else
+ {
+ init += fullIndentString + fieldName + ",\n";
+ }
+ }
+
+ init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
+
+ return init;
+}
+
+void OutputHLSL::header()
+{
+ TInfoSinkBase &out = mHeader;
+
+ TString uniforms;
+ TString interfaceBlocks;
+ TString varyings;
+ TString attributes;
+ TString flaggedStructs;
+
+ for (ReferencedSymbols::const_iterator uniformIt = mReferencedUniforms.begin(); uniformIt != mReferencedUniforms.end(); uniformIt++)
+ {
+ const TIntermSymbol &uniform = *uniformIt->second;
+ const TType &type = uniform.getType();
+ const TString &name = uniform.getSymbol();
+
+ int registerIndex = declareUniformAndAssignRegister(type, name);
+
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
+ {
+ uniforms += "uniform " + samplerString(type) + " sampler_" + decorateUniform(name, type) + arrayString(type) +
+ " : register(s" + str(registerIndex) + ");\n";
+
+ uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) +
+ " : register(t" + str(registerIndex) + ");\n";
+ }
+ else
+ {
+ const TStructure *structure = type.getStruct();
+ const TString &typeName = (structure ? structureTypeName(*structure, false, false) : typeString(type));
+
+ const TString &registerString = TString("register(") + RegisterPrefix(type) + str(registerIndex) + ")";
+
+ uniforms += "uniform " + typeName + " " + decorateUniform(name, type) + arrayString(type) + " : " + registerString + ";\n";
+ }
+ }
+
+ for (ReferencedSymbols::const_iterator interfaceBlockIt = mReferencedInterfaceBlocks.begin(); interfaceBlockIt != mReferencedInterfaceBlocks.end(); interfaceBlockIt++)
+ {
+ const TType &nodeType = interfaceBlockIt->second->getType();
+ const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
+ const TFieldList &fieldList = interfaceBlock.fields();
+
+ unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
+ gl::InterfaceBlock activeBlock(interfaceBlock.name().c_str(), arraySize, mInterfaceBlockRegister);
+ for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
+ {
+ const TField &field = *fieldList[typeIndex];
+ const TString &fullUniformName = interfaceBlockFieldString(interfaceBlock, field);
+ declareInterfaceBlockField(*field.type(), fullUniformName, activeBlock.fields);
+ }
+
+ mInterfaceBlockRegister += std::max(1u, arraySize);
+
+ gl::BlockLayoutType blockLayoutType = convertBlockLayoutType(interfaceBlock.blockStorage());
+ setBlockLayout(&activeBlock, blockLayoutType);
+
+ if (interfaceBlock.matrixPacking() == EmpRowMajor)
+ {
+ activeBlock.isRowMajorLayout = true;
+ }
+
+ mActiveInterfaceBlocks.push_back(activeBlock);
+
+ if (interfaceBlock.hasInstanceName())
+ {
+ interfaceBlocks += interfaceBlockStructString(interfaceBlock);
+ }
+
+ if (arraySize > 0)
+ {
+ for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
+ {
+ interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex + arrayIndex, arrayIndex);
+ }
+ }
+ else
+ {
+ interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex, GL_INVALID_INDEX);
+ }
+ }
+
+ for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
+ {
+ TIntermTyped *structNode = flaggedStructIt->first;
+ const TString &mappedName = flaggedStructIt->second;
+ const TStructure &structure = *structNode->getType().getStruct();
+ const TString &originalName = mFlaggedStructOriginalNames[structNode];
+
+ flaggedStructs += "static " + decorate(structure.name()) + " " + mappedName + " =\n";
+ flaggedStructs += structInitializerString(0, structure, originalName);
+ flaggedStructs += "\n";
+ }
+
+ for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
+ {
+ const TType &type = varying->second->getType();
+ const TString &name = varying->second->getSymbol();
+
+ // Program linking depends on this exact format
+ varyings += "static " + interpolationString(type.getQualifier()) + " " + typeString(type) + " " +
+ decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+
+ declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings);
+ }
+
+ for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
+ {
+ const TType &type = attribute->second->getType();
+ const TString &name = attribute->second->getSymbol();
+
+ attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+
+ gl::Attribute attributeVar(glVariableType(type), glVariablePrecision(type), name.c_str(),
+ (unsigned int)type.getArraySize(), type.getLayoutQualifier().location);
+ mActiveAttributes.push_back(attributeVar);
+ }
+
+ for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
+ {
+ out << *structDeclaration;
+ }
+
+ for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
+ {
+ out << *constructor;
+ }
+
+ if (mUsesDiscardRewriting)
+ {
+ out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
+ }
+
+ if (mUsesNestedBreak)
+ {
+ out << "#define ANGLE_USES_NESTED_BREAK" << "\n";
+ }
+
+ if (mContext.shaderType == SH_FRAGMENT_SHADER)
+ {
+ TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
+ const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
+
+ out << "// Varyings\n";
+ out << varyings;
+ out << "\n";
+
+ if (mContext.getShaderVersion() >= 300)
+ {
+ for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
+ {
+ const TString &variableName = outputVariableIt->first;
+ const TType &variableType = outputVariableIt->second->getType();
+ const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier();
+
+ out << "static " + typeString(variableType) + " out_" + variableName + arrayString(variableType) +
+ " = " + initializer(variableType) + ";\n";
+
+ gl::Attribute outputVar(glVariableType(variableType), glVariablePrecision(variableType), variableName.c_str(),
+ (unsigned int)variableType.getArraySize(), layoutQualifier.location);
+ mActiveOutputVariables.push_back(outputVar);
+ }
+ }
+ else
+ {
+ const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
+
+ out << "static float4 gl_Color[" << numColorValues << "] =\n"
+ "{\n";
+ for (unsigned int i = 0; i < numColorValues; i++)
+ {
+ out << " float4(0, 0, 0, 0)";
+ if (i + 1 != numColorValues)
+ {
+ out << ",";
+ }
+ out << "\n";
+ }
+
+ out << "};\n";
+ }
+
+ if (mUsesFragDepth)
+ {
+ out << "static float gl_Depth = 0.0;\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "static bool gl_FrontFacing = false;\n";
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n";
+
+ if (mUsesDepthRange)
+ {
+ out << " float3 dx_DepthRange : packoffset(c0);\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << " float4 dx_ViewCoords : packoffset(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << " float3 dx_DepthFront : packoffset(c2);\n";
+ }
+
+ out << "};\n";
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "uniform float4 dx_ViewCoords : register(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << "uniform float3 dx_DepthFront : register(c2);\n";
+ }
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ out << uniforms;
+ out << "\n";
+
+ if (!interfaceBlocks.empty())
+ {
+ out << interfaceBlocks;
+ out << "\n";
+
+ if (!flaggedStructs.empty())
+ {
+ out << "// Std140 Structures accessed by value\n";
+ out << "\n";
+ out << flaggedStructs;
+ out << "\n";
+ }
+ }
+
+ if (usingMRTExtension && mNumRenderTargets > 1)
+ {
+ out << "#define GL_USES_MRT\n";
+ }
+
+ if (mUsesFragColor)
+ {
+ out << "#define GL_USES_FRAG_COLOR\n";
+ }
+
+ if (mUsesFragData)
+ {
+ out << "#define GL_USES_FRAG_DATA\n";
+ }
+ }
+ else // Vertex shader
+ {
+ out << "// Attributes\n";
+ out << attributes;
+ out << "\n"
+ "static float4 gl_Position = float4(0, 0, 0, 0);\n";
+
+ if (mUsesPointSize)
+ {
+ out << "static float gl_PointSize = float(1);\n";
+ }
+
+ out << "\n"
+ "// Varyings\n";
+ out << varyings;
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ if (mUsesDepthRange)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n"
+ " float3 dx_DepthRange : packoffset(c0);\n"
+ "};\n"
+ "\n";
+ }
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);\n";
+ }
+
+ out << "uniform float4 dx_ViewAdjust : register(c1);\n"
+ "\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ out << uniforms;
+ out << "\n";
+
+ if (!interfaceBlocks.empty())
+ {
+ out << interfaceBlocks;
+ out << "\n";
+
+ if (!flaggedStructs.empty())
+ {
+ out << "// Std140 Structures accessed by value\n";
+ out << "\n";
+ out << flaggedStructs;
+ out << "\n";
+ }
+ }
+ }
+
+ for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
+ {
+ // Return type
+ if (textureFunction->method == TextureFunction::SIZE)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << "int2 "; break;
+ case EbtSampler3D: out << "int3 "; break;
+ case EbtSamplerCube: out << "int2 "; break;
+ case EbtSampler2DArray: out << "int3 "; break;
+ case EbtISampler2D: out << "int2 "; break;
+ case EbtISampler3D: out << "int3 "; break;
+ case EbtISamplerCube: out << "int2 "; break;
+ case EbtISampler2DArray: out << "int3 "; break;
+ case EbtUSampler2D: out << "int2 "; break;
+ case EbtUSampler3D: out << "int3 "; break;
+ case EbtUSamplerCube: out << "int2 "; break;
+ case EbtUSampler2DArray: out << "int3 "; break;
+ case EbtSampler2DShadow: out << "int2 "; break;
+ case EbtSamplerCubeShadow: out << "int2 "; break;
+ case EbtSampler2DArrayShadow: out << "int3 "; break;
+ default: UNREACHABLE();
+ }
+ }
+ else // Sampling function
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << "float4 "; break;
+ case EbtSampler3D: out << "float4 "; break;
+ case EbtSamplerCube: out << "float4 "; break;
+ case EbtSampler2DArray: out << "float4 "; break;
+ case EbtISampler2D: out << "int4 "; break;
+ case EbtISampler3D: out << "int4 "; break;
+ case EbtISamplerCube: out << "int4 "; break;
+ case EbtISampler2DArray: out << "int4 "; break;
+ case EbtUSampler2D: out << "uint4 "; break;
+ case EbtUSampler3D: out << "uint4 "; break;
+ case EbtUSamplerCube: out << "uint4 "; break;
+ case EbtUSampler2DArray: out << "uint4 "; break;
+ case EbtSampler2DShadow: out << "float "; break;
+ case EbtSamplerCubeShadow: out << "float "; break;
+ case EbtSampler2DArrayShadow: out << "float "; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ // Function name
+ out << textureFunction->name();
+
+ // Argument list
+ int hlslCoords = 4;
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break;
+ case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break;
+ default: UNREACHABLE();
+ }
+
+ switch(textureFunction->method)
+ {
+ case TextureFunction::IMPLICIT: break;
+ case TextureFunction::BIAS: hlslCoords = 4; break;
+ case TextureFunction::LOD: hlslCoords = 4; break;
+ case TextureFunction::LOD0: hlslCoords = 4; break;
+ case TextureFunction::LOD0BIAS: hlslCoords = 4; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
+ case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
+ case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
+ case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
+ case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
+ case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
+ case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
+ case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
+ case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
+ case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
+ {
+ switch(textureFunction->coords)
+ {
+ case 2: out << ", int2 t"; break;
+ case 3: out << ", int3 t"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else // Floating-point coordinates (except textureSize)
+ {
+ switch(textureFunction->coords)
+ {
+ case 1: out << ", int lod"; break; // textureSize()
+ case 2: out << ", float2 t"; break;
+ case 3: out << ", float3 t"; break;
+ case 4: out << ", float4 t"; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ if (textureFunction->method == TextureFunction::GRAD)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ case EbtSampler2DShadow:
+ case EbtSampler2DArrayShadow:
+ out << ", float2 ddx, float2 ddy";
+ break;
+ case EbtSampler3D:
+ case EbtISampler3D:
+ case EbtUSampler3D:
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ case EbtSamplerCubeShadow:
+ out << ", float3 ddx, float3 ddy";
+ break;
+ default: UNREACHABLE();
+ }
+ }
+
+ switch(textureFunction->method)
+ {
+ case TextureFunction::IMPLICIT: break;
+ case TextureFunction::BIAS: break; // Comes after the offset parameter
+ case TextureFunction::LOD: out << ", float lod"; break;
+ case TextureFunction::LOD0: break;
+ case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter
+ case TextureFunction::SIZE: break;
+ case TextureFunction::FETCH: out << ", int mip"; break;
+ case TextureFunction::GRAD: break;
+ default: UNREACHABLE();
+ }
+
+ if (textureFunction->offset)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << ", int2 offset"; break;
+ case EbtSampler3D: out << ", int3 offset"; break;
+ case EbtSampler2DArray: out << ", int2 offset"; break;
+ case EbtISampler2D: out << ", int2 offset"; break;
+ case EbtISampler3D: out << ", int3 offset"; break;
+ case EbtISampler2DArray: out << ", int2 offset"; break;
+ case EbtUSampler2D: out << ", int2 offset"; break;
+ case EbtUSampler3D: out << ", int3 offset"; break;
+ case EbtUSampler2DArray: out << ", int2 offset"; break;
+ case EbtSampler2DShadow: out << ", int2 offset"; break;
+ case EbtSampler2DArrayShadow: out << ", int2 offset"; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ if (textureFunction->method == TextureFunction::BIAS ||
+ textureFunction->method == TextureFunction::LOD0BIAS)
+ {
+ out << ", float bias";
+ }
+
+ out << ")\n"
+ "{\n";
+
+ if (textureFunction->method == TextureFunction::SIZE)
+ {
+ if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
+ {
+ if (IsSamplerArray(textureFunction->sampler))
+ {
+ out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
+ " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
+ }
+ else
+ {
+ out << " uint width; uint height; uint numberOfLevels;\n"
+ " x.GetDimensions(lod, width, height, numberOfLevels);\n";
+ }
+ }
+ else if (IsSampler3D(textureFunction->sampler))
+ {
+ out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
+ " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
+ }
+ else UNREACHABLE();
+
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << " return int2(width, height);"; break;
+ case EbtSampler3D: out << " return int3(width, height, depth);"; break;
+ case EbtSamplerCube: out << " return int2(width, height);"; break;
+ case EbtSampler2DArray: out << " return int3(width, height, layers);"; break;
+ case EbtISampler2D: out << " return int2(width, height);"; break;
+ case EbtISampler3D: out << " return int3(width, height, depth);"; break;
+ case EbtISamplerCube: out << " return int2(width, height);"; break;
+ case EbtISampler2DArray: out << " return int3(width, height, layers);"; break;
+ case EbtUSampler2D: out << " return int2(width, height);"; break;
+ case EbtUSampler3D: out << " return int3(width, height, depth);"; break;
+ case EbtUSamplerCube: out << " return int2(width, height);"; break;
+ case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break;
+ case EbtSampler2DShadow: out << " return int2(width, height);"; break;
+ case EbtSamplerCubeShadow: out << " return int2(width, height);"; break;
+ case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else
+ {
+ if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
+ {
+ out << " float width; float height; float layers; float levels;\n";
+
+ out << " uint mip = 0;\n";
+
+ out << " x.GetDimensions(mip, width, height, layers, levels);\n";
+
+ out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
+ out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
+ out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n";
+ out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n";
+
+ // FACE_POSITIVE_X = 000b
+ // FACE_NEGATIVE_X = 001b
+ // FACE_POSITIVE_Y = 010b
+ // FACE_NEGATIVE_Y = 011b
+ // FACE_POSITIVE_Z = 100b
+ // FACE_NEGATIVE_Z = 101b
+ out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n";
+
+ out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n";
+ out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n";
+ out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n";
+
+ out << " t.x = (u * 0.5f / m) + 0.5f;\n";
+ out << " t.y = (v * 0.5f / m) + 0.5f;\n";
+ }
+ else if (IsIntegerSampler(textureFunction->sampler) &&
+ textureFunction->method != TextureFunction::FETCH)
+ {
+ if (IsSampler2D(textureFunction->sampler))
+ {
+ if (IsSamplerArray(textureFunction->sampler))
+ {
+ out << " float width; float height; float layers; float levels;\n";
+
+ if (textureFunction->method == TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction->method == TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+ if (textureFunction->method == TextureFunction::IMPLICIT ||
+ textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " x.GetDimensions(0, width, height, layers, levels);\n"
+ " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction->method == TextureFunction::GRAD)
+ {
+ out << " x.GetDimensions(0, width, height, layers, levels);\n"
+ " float lod = log2(max(length(ddx), length(ddy)));\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " x.GetDimensions(mip, width, height, layers, levels);\n";
+ }
+ else
+ {
+ out << " float width; float height; float levels;\n";
+
+ if (textureFunction->method == TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction->method == TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+ if (textureFunction->method == TextureFunction::IMPLICIT ||
+ textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " x.GetDimensions(0, width, height, levels);\n"
+ " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction->method == TextureFunction::LOD)
+ {
+ out << " x.GetDimensions(0, width, height, levels);\n";
+ }
+ else if (textureFunction->method == TextureFunction::GRAD)
+ {
+ out << " x.GetDimensions(0, width, height, levels);\n"
+ " float lod = log2(max(length(ddx), length(ddy)));\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " x.GetDimensions(mip, width, height, levels);\n";
+ }
+ }
+ else if (IsSampler3D(textureFunction->sampler))
+ {
+ out << " float width; float height; float depth; float levels;\n";
+
+ if (textureFunction->method == TextureFunction::LOD0)
+ {
+ out << " uint mip = 0;\n";
+ }
+ else if (textureFunction->method == TextureFunction::LOD0BIAS)
+ {
+ out << " uint mip = bias;\n";
+ }
+ else
+ {
+ if (textureFunction->method == TextureFunction::IMPLICIT ||
+ textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " x.GetDimensions(0, width, height, depth, levels);\n"
+ " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
+ " float dx = length(ddx(tSized));\n"
+ " float dy = length(ddy(tSized));\n"
+ " float lod = log2(max(dx, dy));\n";
+
+ if (textureFunction->method == TextureFunction::BIAS)
+ {
+ out << " lod += bias;\n";
+ }
+ }
+ else if (textureFunction->method == TextureFunction::GRAD)
+ {
+ out << " x.GetDimensions(0, width, height, depth, levels);\n"
+ " float lod = log2(max(length(ddx), length(ddy)));\n";
+ }
+
+ out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
+ }
+
+ out << " x.GetDimensions(mip, width, height, depth, levels);\n";
+ }
+ else UNREACHABLE();
+ }
+
+ out << " return ";
+
+ // HLSL intrinsic
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ switch(textureFunction->sampler)
+ {
+ case EbtSampler2D: out << "tex2D"; break;
+ case EbtSamplerCube: out << "texCUBE"; break;
+ default: UNREACHABLE();
+ }
+
+ switch(textureFunction->method)
+ {
+ case TextureFunction::IMPLICIT: out << "(s, "; break;
+ case TextureFunction::BIAS: out << "bias(s, "; break;
+ case TextureFunction::LOD: out << "lod(s, "; break;
+ case TextureFunction::LOD0: out << "lod(s, "; break;
+ case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ if (textureFunction->method == TextureFunction::GRAD)
+ {
+ if (IsIntegerSampler(textureFunction->sampler))
+ {
+ out << "x.Load(";
+ }
+ else if (IsShadowSampler(textureFunction->sampler))
+ {
+ out << "x.SampleCmpLevelZero(s, ";
+ }
+ else
+ {
+ out << "x.SampleGrad(s, ";
+ }
+ }
+ else if (IsIntegerSampler(textureFunction->sampler) ||
+ textureFunction->method == TextureFunction::FETCH)
+ {
+ out << "x.Load(";
+ }
+ else if (IsShadowSampler(textureFunction->sampler))
+ {
+ out << "x.SampleCmp(s, ";
+ }
+ else
+ {
+ switch(textureFunction->method)
+ {
+ case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
+ case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
+ case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
+ case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
+ case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+ else UNREACHABLE();
+
+ // Integer sampling requires integer addresses
+ TString addressx = "";
+ TString addressy = "";
+ TString addressz = "";
+ TString close = "";
+
+ if (IsIntegerSampler(textureFunction->sampler) ||
+ textureFunction->method == TextureFunction::FETCH)
+ {
+ switch(hlslCoords)
+ {
+ case 2: out << "int3("; break;
+ case 3: out << "int4("; break;
+ default: UNREACHABLE();
+ }
+
+ // Convert from normalized floating-point to integer
+ if (textureFunction->method != TextureFunction::FETCH)
+ {
+ addressx = "int(floor(width * frac((";
+ addressy = "int(floor(height * frac((";
+
+ if (IsSamplerArray(textureFunction->sampler))
+ {
+ addressz = "int(max(0, min(layers - 1, floor(0.5 + ";
+ }
+ else if (IsSamplerCube(textureFunction->sampler))
+ {
+ addressz = "((((";
+ }
+ else
+ {
+ addressz = "int(floor(depth * frac((";
+ }
+
+ close = "))))";
+ }
+ }
+ else
+ {
+ switch(hlslCoords)
+ {
+ case 2: out << "float2("; break;
+ case 3: out << "float3("; break;
+ case 4: out << "float4("; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ TString proj = ""; // Only used for projected textures
+
+ if (textureFunction->proj)
+ {
+ switch(textureFunction->coords)
+ {
+ case 3: proj = " / t.z"; break;
+ case 4: proj = " / t.w"; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ if (hlslCoords >= 3)
+ {
+ if (textureFunction->coords < 3)
+ {
+ out << ", 0";
+ }
+ else
+ {
+ out << ", t.z" + proj;
+ }
+ }
+
+ if (hlslCoords == 4)
+ {
+ switch(textureFunction->method)
+ {
+ case TextureFunction::BIAS: out << ", bias"; break;
+ case TextureFunction::LOD: out << ", lod"; break;
+ case TextureFunction::LOD0: out << ", 0"; break;
+ case TextureFunction::LOD0BIAS: out << ", bias"; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ out << "));\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ if (hlslCoords >= 3)
+ {
+ if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
+ {
+ out << ", face";
+ }
+ else
+ {
+ out << ", " + addressz + ("t.z" + proj) + close;
+ }
+ }
+
+ if (textureFunction->method == TextureFunction::GRAD)
+ {
+ if (IsIntegerSampler(textureFunction->sampler))
+ {
+ out << ", mip)";
+ }
+ else if (IsShadowSampler(textureFunction->sampler))
+ {
+ // Compare value
+ switch(textureFunction->coords)
+ {
+ case 3: out << "), t.z"; break;
+ case 4: out << "), t.w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else
+ {
+ out << "), ddx, ddy";
+ }
+ }
+ else if (IsIntegerSampler(textureFunction->sampler) ||
+ textureFunction->method == TextureFunction::FETCH)
+ {
+ out << ", mip)";
+ }
+ else if (IsShadowSampler(textureFunction->sampler))
+ {
+ // Compare value
+ switch(textureFunction->coords)
+ {
+ case 3: out << "), t.z"; break;
+ case 4: out << "), t.w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else
+ {
+ switch(textureFunction->method)
+ {
+ case TextureFunction::IMPLICIT: out << ")"; break;
+ case TextureFunction::BIAS: out << "), bias"; break;
+ case TextureFunction::LOD: out << "), lod"; break;
+ case TextureFunction::LOD0: out << "), 0"; break;
+ case TextureFunction::LOD0BIAS: out << "), bias"; break;
+ default: UNREACHABLE();
+ }
+ }
+
+ if (textureFunction->offset)
+ {
+ out << ", offset";
+ }
+
+ out << ");";
+ }
+ else UNREACHABLE();
+ }
+
+ out << "\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "#define GL_USES_FRAG_COORD\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "#define GL_USES_POINT_COORD\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "#define GL_USES_FRONT_FACING\n";
+ }
+
+ if (mUsesPointSize)
+ {
+ out << "#define GL_USES_POINT_SIZE\n";
+ }
+
+ if (mUsesFragDepth)
+ {
+ out << "#define GL_USES_FRAG_DEPTH\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "#define GL_USES_DEPTH_RANGE\n";
+ }
+
+ if (mUsesXor)
+ {
+ out << "bool xor(bool p, bool q)\n"
+ "{\n"
+ " return (p || q) && !(p && q);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod1)
+ {
+ out << "float mod(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2v)
+ {
+ out << "float2 mod(float2 x, float2 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2f)
+ {
+ out << "float2 mod(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3v)
+ {
+ out << "float3 mod(float3 x, float3 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3f)
+ {
+ out << "float3 mod(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4v)
+ {
+ out << "float4 mod(float4 x, float4 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4f)
+ {
+ out << "float4 mod(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward1)
+ {
+ out << "float faceforward(float N, float I, float Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward2)
+ {
+ out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward3)
+ {
+ out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward4)
+ {
+ out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesAtan2_1)
+ {
+ out << "float atanyx(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
+ " return atan2(y, x);\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_2)
+ {
+ out << "float2 atanyx(float2 y, float2 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_3)
+ {
+ out << "float3 atanyx(float3 y, float3 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_4)
+ {
+ out << "float4 atanyx(float4 y, float4 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
+ " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
+ "}\n";
+ }
+}
+
+void OutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ // Handle accessing std140 structs by value
+ if (mFlaggedStructMappedNames.count(node) > 0)
+ {
+ out << mFlaggedStructMappedNames[node];
+ return;
+ }
+
+ TString name = node->getSymbol();
+
+ if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else
+ {
+ TQualifier qualifier = node->getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ const TType& nodeType = node->getType();
+ const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock();
+
+ if (interfaceBlock)
+ {
+ mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
+ }
+ else
+ {
+ mReferencedUniforms[name] = node;
+ }
+
+ out << decorateUniform(name, nodeType);
+ }
+ else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
+ {
+ mReferencedAttributes[name] = node;
+ out << decorate(name);
+ }
+ else if (isVarying(qualifier))
+ {
+ mReferencedVaryings[name] = node;
+ out << decorate(name);
+ }
+ else if (qualifier == EvqFragmentOut)
+ {
+ mReferencedOutputVariables[name] = node;
+ out << "out_" << name;
+ }
+ else if (qualifier == EvqFragColor)
+ {
+ out << "gl_Color[0]";
+ mUsesFragColor = true;
+ }
+ else if (qualifier == EvqFragData)
+ {
+ out << "gl_Color";
+ mUsesFragData = true;
+ }
+ else if (qualifier == EvqFragCoord)
+ {
+ mUsesFragCoord = true;
+ out << name;
+ }
+ else if (qualifier == EvqPointCoord)
+ {
+ mUsesPointCoord = true;
+ out << name;
+ }
+ else if (qualifier == EvqFrontFacing)
+ {
+ mUsesFrontFacing = true;
+ out << name;
+ }
+ else if (qualifier == EvqPointSize)
+ {
+ mUsesPointSize = true;
+ out << name;
+ }
+ else if (name == "gl_FragDepthEXT")
+ {
+ mUsesFragDepth = true;
+ out << "gl_Depth";
+ }
+ else if (qualifier == EvqInternal)
+ {
+ out << name;
+ }
+ else
+ {
+ out << decorate(name);
+ }
+ }
+}
+
+void OutputHLSL::visitRaw(TIntermRaw *node)
+{
+ mBody << node->getRawText();
+}
+
+bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ // Handle accessing std140 structs by value
+ if (mFlaggedStructMappedNames.count(node) > 0)
+ {
+ out << mFlaggedStructMappedNames[node];
+ return false;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ // GLSL allows to write things like "float x = x;" where a new variable x is defined
+ // and the value of an existing variable x is assigned. HLSL uses C semantics (the
+ // new variable is created before the assignment is evaluated), so we need to convert
+ // this to "float t = x, x = t;".
+
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ TIntermTyped *expression = node->getRight();
+
+ sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
+ expression->traverse(&searchSymbol);
+ bool sameSymbol = searchSymbol.foundMatch();
+
+ if (sameSymbol)
+ {
+ // Type already printed
+ out << "t" + str(mUniqueIndex) + " = ";
+ expression->traverse(this);
+ out << ", ";
+ symbolNode->traverse(this);
+ out << " = t" + str(mUniqueIndex);
+
+ mUniqueIndex++;
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ }
+ break;
+ case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
+ case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", transpose(";
+ }
+ else
+ {
+ out << ")))";
+ }
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", ";
+ }
+ else
+ {
+ out << "))";
+ }
+ break;
+ case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
+ case EOpIndexDirect:
+ {
+ const TType& leftType = node->getLeft()->getType();
+ if (leftType.isInterfaceBlock())
+ {
+ if (visit == PreVisit)
+ {
+ TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
+ const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
+
+ mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
+ out << interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
+
+ return false;
+ }
+ }
+ else
+ {
+ outputTriplet(visit, "", "[", "]");
+ }
+ }
+ break;
+ case EOpIndexIndirect:
+ // We do not currently support indirect references to interface blocks
+ ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
+ outputTriplet(visit, "", "[", "]");
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ const TStructure* structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
+ const TField* field = structure->fields()[index->getIConst(0)];
+ out << "." + decorateField(field->name(), *structure);
+
+ return false;
+ }
+ break;
+ case EOpIndexDirectInterfaceBlock:
+ if (visit == InVisit)
+ {
+ const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
+ const TField* field = interfaceBlock->fields()[index->getIConst(0)];
+ out << "." + decorate(field->name());
+
+ return false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+
+ TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
+
+ if (swizzle)
+ {
+ TIntermSequence &sequence = swizzle->getSequence();
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+
+ if (element)
+ {
+ int i = element->getIConst(0);
+
+ switch (i)
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ return false; // Fully processed
+ }
+ break;
+ case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
+ case EOpEqual:
+ case EOpNotEqual:
+ if (node->getLeft()->isScalar())
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "(", " != ", ")");
+ }
+ }
+ else if (node->getLeft()->getBasicType() == EbtStruct)
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ out << "(";
+ }
+ else
+ {
+ out << "!(";
+ }
+
+ const TStructure &structure = *node->getLeft()->getType().getStruct();
+ const TFieldList &fields = structure.fields();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TField *field = fields[i];
+
+ node->getLeft()->traverse(this);
+ out << "." + decorateField(field->name(), structure) + " == ";
+ node->getRight()->traverse(this);
+ out << "." + decorateField(field->name(), structure);
+
+ if (i < fields.size() - 1)
+ {
+ out << " && ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ else
+ {
+ ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
+
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "all(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "!all(", " == ", ")");
+ }
+ }
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
+ case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
+ case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
+ case EOpLogicalOr:
+ if (node->getRight()->hasSideEffects())
+ {
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ }
+ else
+ {
+ outputTriplet(visit, "(", " || ", ")");
+ return true;
+ }
+ case EOpLogicalXor:
+ mUsesXor = true;
+ outputTriplet(visit, "xor(", ", ", ")");
+ break;
+ case EOpLogicalAnd:
+ if (node->getRight()->hasSideEffects())
+ {
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ }
+ else
+ {
+ outputTriplet(visit, "(", " && ", ")");
+ return true;
+ }
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
+ case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
+ case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
+ case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
+ case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
+ case EOpConvIntToBool:
+ case EOpConvUIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "bool(", "", ")"); break;
+ case 2: outputTriplet(visit, "bool2(", "", ")"); break;
+ case 3: outputTriplet(visit, "bool3(", "", ")"); break;
+ case 4: outputTriplet(visit, "bool4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ case EOpConvUIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "float(", "", ")"); break;
+ case 2: outputTriplet(visit, "float2(", "", ")"); break;
+ case 3: outputTriplet(visit, "float3(", "", ")"); break;
+ case 4: outputTriplet(visit, "float4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ case EOpConvUIntToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "int(", "", ")"); break;
+ case 2: outputTriplet(visit, "int2(", "", ")"); break;
+ case 3: outputTriplet(visit, "int3(", "", ")"); break;
+ case 4: outputTriplet(visit, "int4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToUInt:
+ case EOpConvBoolToUInt:
+ case EOpConvIntToUInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "uint(", "", ")"); break;
+ case 2: outputTriplet(visit, "uint2(", "", ")"); break;
+ case 3: outputTriplet(visit, "uint3(", "", ")"); break;
+ case 4: outputTriplet(visit, "uint4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
+ case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
+ case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
+ case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
+ case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
+ case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
+ case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
+ case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
+ case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
+ case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
+ case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
+ case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
+ case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
+ case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
+ case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
+ case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
+ case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
+ case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
+ case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
+ case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
+ case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
+ case EOpDFdx:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddx(", "", ")");
+ }
+ break;
+ case EOpDFdy:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddy(", "", ")");
+ }
+ break;
+ case EOpFwidth:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "fwidth(", "", ")");
+ }
+ break;
+ case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
+ case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ {
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+ }
+
+ for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
+ {
+ outputLineDirective((*sit)->getLine().first_line);
+
+ traverseStatements(*sit);
+
+ out << ";\n";
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine().last_line);
+ out << "}\n";
+ }
+
+ return false;
+ }
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ TIntermSequence &sequence = node->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+ {
+ if (variable->getType().getStruct())
+ {
+ addConstructor(variable->getType(), structNameString(*variable->getType().getStruct()), NULL);
+ }
+
+ if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
+ {
+ if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << typeString(variable->getType()) + " ";
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << arrayString(symbol->getType());
+ out << " = " + initializer(symbol->getType());
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+
+ if (*sit != sequence.back())
+ {
+ out << ", ";
+ }
+ }
+ }
+ else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
+ {
+ // Already added to constructor map
+ }
+ else UNREACHABLE();
+ }
+ else if (variable && isVaryingOut(variable->getQualifier()))
+ {
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
+ mReferencedVaryings[symbol->getSymbol()] = symbol;
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+ }
+ }
+
+ return false;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ break;
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
+
+ TIntermSequence &arguments = node->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ");\n";
+
+ // Also prototype the Lod0 variant if needed
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+ }
+ break;
+ case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
+ case EOpFunction:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ out << typeString(node->getType()) << " ";
+
+ if (name == "main")
+ {
+ out << "gl_main(";
+ }
+ else
+ {
+ out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
+ }
+
+ TIntermSequence &sequence = node->getSequence();
+ TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ if (symbol->getType().getStruct())
+ {
+ addConstructor(symbol->getType(), structNameString(*symbol->getType().getStruct()), NULL);
+ }
+
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ")\n"
+ "{\n";
+
+ if (sequence.size() > 1)
+ {
+ mInsideFunction = true;
+ sequence[1]->traverse(this);
+ mInsideFunction = false;
+ }
+
+ out << "}\n";
+
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ if (name != "main")
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+ }
+
+ return false;
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+ bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
+ TIntermSequence &arguments = node->getSequence();
+
+ if (node->isUserDefined())
+ {
+ out << decorate(name) << (lod0 ? "Lod0(" : "(");
+ }
+ else
+ {
+ TBasicType samplerType = arguments[0]->getAsTyped()->getType().getBasicType();
+
+ TextureFunction textureFunction;
+ textureFunction.sampler = samplerType;
+ textureFunction.coords = arguments[1]->getAsTyped()->getNominalSize();
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.proj = false;
+ textureFunction.offset = false;
+
+ if (name == "texture2D" || name == "textureCube" || name == "texture")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ }
+ else if (name == "texture2DProj" || name == "textureProj")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.proj = true;
+ }
+ else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" ||
+ name == "texture2DLodEXT" || name == "textureCubeLodEXT")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ }
+ else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureSize")
+ {
+ textureFunction.method = TextureFunction::SIZE;
+ }
+ else if (name == "textureOffset")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjOffset")
+ {
+ textureFunction.method = TextureFunction::IMPLICIT;
+ textureFunction.offset = true;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureLodOffset")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjLodOffset")
+ {
+ textureFunction.method = TextureFunction::LOD;
+ textureFunction.proj = true;
+ textureFunction.offset = true;
+ }
+ else if (name == "texelFetch")
+ {
+ textureFunction.method = TextureFunction::FETCH;
+ }
+ else if (name == "texelFetchOffset")
+ {
+ textureFunction.method = TextureFunction::FETCH;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureGrad" || name == "texture2DGradEXT")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ }
+ else if (name == "textureGradOffset")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.offset = true;
+ }
+ else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.proj = true;
+ }
+ else if (name == "textureProjGradOffset")
+ {
+ textureFunction.method = TextureFunction::GRAD;
+ textureFunction.proj = true;
+ textureFunction.offset = true;
+ }
+ else UNREACHABLE();
+
+ if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument
+ {
+ unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments
+
+ if (textureFunction.offset)
+ {
+ mandatoryArgumentCount++;
+ }
+
+ bool bias = (arguments.size() > mandatoryArgumentCount); // Bias argument is optional
+
+ if (lod0 || mContext.shaderType == SH_VERTEX_SHADER)
+ {
+ if (bias)
+ {
+ textureFunction.method = TextureFunction::LOD0BIAS;
+ }
+ else
+ {
+ textureFunction.method = TextureFunction::LOD0;
+ }
+ }
+ else if (bias)
+ {
+ textureFunction.method = TextureFunction::BIAS;
+ }
+ }
+
+ mUsesTexture.insert(textureFunction);
+
+ out << textureFunction.name();
+ }
+
+ for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
+ {
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
+ {
+ out << "texture_";
+ (*arg)->traverse(this);
+ out << ", sampler_";
+ }
+
+ (*arg)->traverse(this);
+
+ if (arg < arguments.end() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ break;
+ case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
+ case EOpConstructFloat:
+ addConstructor(node->getType(), "vec1", &node->getSequence());
+ outputTriplet(visit, "vec1(", "", ")");
+ break;
+ case EOpConstructVec2:
+ addConstructor(node->getType(), "vec2", &node->getSequence());
+ outputTriplet(visit, "vec2(", ", ", ")");
+ break;
+ case EOpConstructVec3:
+ addConstructor(node->getType(), "vec3", &node->getSequence());
+ outputTriplet(visit, "vec3(", ", ", ")");
+ break;
+ case EOpConstructVec4:
+ addConstructor(node->getType(), "vec4", &node->getSequence());
+ outputTriplet(visit, "vec4(", ", ", ")");
+ break;
+ case EOpConstructBool:
+ addConstructor(node->getType(), "bvec1", &node->getSequence());
+ outputTriplet(visit, "bvec1(", "", ")");
+ break;
+ case EOpConstructBVec2:
+ addConstructor(node->getType(), "bvec2", &node->getSequence());
+ outputTriplet(visit, "bvec2(", ", ", ")");
+ break;
+ case EOpConstructBVec3:
+ addConstructor(node->getType(), "bvec3", &node->getSequence());
+ outputTriplet(visit, "bvec3(", ", ", ")");
+ break;
+ case EOpConstructBVec4:
+ addConstructor(node->getType(), "bvec4", &node->getSequence());
+ outputTriplet(visit, "bvec4(", ", ", ")");
+ break;
+ case EOpConstructInt:
+ addConstructor(node->getType(), "ivec1", &node->getSequence());
+ outputTriplet(visit, "ivec1(", "", ")");
+ break;
+ case EOpConstructIVec2:
+ addConstructor(node->getType(), "ivec2", &node->getSequence());
+ outputTriplet(visit, "ivec2(", ", ", ")");
+ break;
+ case EOpConstructIVec3:
+ addConstructor(node->getType(), "ivec3", &node->getSequence());
+ outputTriplet(visit, "ivec3(", ", ", ")");
+ break;
+ case EOpConstructIVec4:
+ addConstructor(node->getType(), "ivec4", &node->getSequence());
+ outputTriplet(visit, "ivec4(", ", ", ")");
+ break;
+ case EOpConstructUInt:
+ addConstructor(node->getType(), "uvec1", &node->getSequence());
+ outputTriplet(visit, "uvec1(", "", ")");
+ break;
+ case EOpConstructUVec2:
+ addConstructor(node->getType(), "uvec2", &node->getSequence());
+ outputTriplet(visit, "uvec2(", ", ", ")");
+ break;
+ case EOpConstructUVec3:
+ addConstructor(node->getType(), "uvec3", &node->getSequence());
+ outputTriplet(visit, "uvec3(", ", ", ")");
+ break;
+ case EOpConstructUVec4:
+ addConstructor(node->getType(), "uvec4", &node->getSequence());
+ outputTriplet(visit, "uvec4(", ", ", ")");
+ break;
+ case EOpConstructMat2:
+ addConstructor(node->getType(), "mat2", &node->getSequence());
+ outputTriplet(visit, "mat2(", ", ", ")");
+ break;
+ case EOpConstructMat3:
+ addConstructor(node->getType(), "mat3", &node->getSequence());
+ outputTriplet(visit, "mat3(", ", ", ")");
+ break;
+ case EOpConstructMat4:
+ addConstructor(node->getType(), "mat4", &node->getSequence());
+ outputTriplet(visit, "mat4(", ", ", ")");
+ break;
+ case EOpConstructStruct:
+ {
+ const TString &structName = structNameString(*node->getType().getStruct());
+ addConstructor(node->getType(), structName, &node->getSequence());
+ outputTriplet(visit, structName + "_ctor(", ", ", ")");
+ }
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
+ case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
+ case EOpMod:
+ {
+ // We need to look at the number of components in both arguments
+ const int modValue = node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
+ + node->getSequence()[1]->getAsTyped()->getNominalSize();
+ switch (modValue)
+ {
+ case 11: mUsesMod1 = true; break;
+ case 22: mUsesMod2v = true; break;
+ case 21: mUsesMod2f = true; break;
+ case 33: mUsesMod3v = true; break;
+ case 31: mUsesMod3f = true; break;
+ case 44: mUsesMod4v = true; break;
+ case 41: mUsesMod4f = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "mod(", ", ", ")");
+ }
+ break;
+ case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpAtan:
+ ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
+ {
+ case 1: mUsesAtan2_1 = true; break;
+ case 2: mUsesAtan2_2 = true; break;
+ case 3: mUsesAtan2_3 = true; break;
+ case 4: mUsesAtan2_4 = true; break;
+ default: UNREACHABLE();
+ }
+ outputTriplet(visit, "atanyx(", ", ", ")");
+ break;
+ case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
+ case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
+ case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
+ case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
+ case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpFaceForward:
+ {
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
+ {
+ case 1: mUsesFaceforward1 = true; break;
+ case 2: mUsesFaceforward2 = true; break;
+ case 3: mUsesFaceforward3 = true; break;
+ case 4: mUsesFaceforward4 = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "faceforward(", ", ", ")");
+ }
+ break;
+ case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (node->usesTernaryOperator())
+ {
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ }
+ else // if/else statement
+ {
+ mUnfoldShortCircuit->traverse(node->getCondition());
+
+ out << "if (";
+
+ node->getCondition()->traverse(this);
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+
+ bool discard = false;
+
+ if (node->getTrueBlock())
+ {
+ traverseStatements(node->getTrueBlock());
+
+ // Detect true discard
+ discard = (discard || FindDiscard::search(node->getTrueBlock()));
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";\n}\n";
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ out << "{\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ traverseStatements(node->getFalseBlock());
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ out << ";\n}\n";
+
+ // Detect false discard
+ discard = (discard || FindDiscard::search(node->getFalseBlock()));
+ }
+
+ // ANGLE issue 486: Detect problematic conditional discard
+ if (discard && FindSideEffectRewriting::search(node))
+ {
+ mUsesDiscardRewriting = true;
+ }
+ }
+
+ return false;
+}
+
+void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
+{
+ mNestedLoopDepth++;
+
+ bool wasDiscontinuous = mInsideDiscontinuousLoop;
+
+ if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
+ {
+ mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
+ }
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ if (handleExcessiveLoop(node))
+ {
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+ mNestedLoopDepth--;
+
+ return false;
+ }
+ }
+
+ TInfoSinkBase &out = mBody;
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ out << "{do\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+ }
+ else
+ {
+ out << "{for(";
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+ }
+
+ if (node->getBody())
+ {
+ traverseStatements(node->getBody());
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";}\n";
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ outputLineDirective(node->getCondition()->getLine().first_line);
+ out << "while(\n";
+
+ node->getCondition()->traverse(this);
+
+ out << ");";
+ }
+
+ out << "}\n";
+
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+ mNestedLoopDepth--;
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ outputTriplet(visit, "discard;\n", "", "");
+ break;
+ case EOpBreak:
+ if (visit == PreVisit)
+ {
+ if (mNestedLoopDepth > 1)
+ {
+ mUsesNestedBreak = true;
+ }
+
+ if (mExcessiveLoopIndex)
+ {
+ out << "{Break";
+ mExcessiveLoopIndex->traverse(this);
+ out << " = true; break;}\n";
+ }
+ else
+ {
+ out << "break;\n";
+ }
+ }
+ break;
+ case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ {
+ if (node->getExpression())
+ {
+ out << "return ";
+ }
+ else
+ {
+ out << "return;\n";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getExpression())
+ {
+ out << ";\n";
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+void OutputHLSL::traverseStatements(TIntermNode *node)
+{
+ if (isSingleStatement(node))
+ {
+ mUnfoldShortCircuit->traverse(node);
+ }
+
+ node->traverse(this);
+}
+
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ TIntermAggregate *aggregate = node->getAsAggregate();
+
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpSequence)
+ {
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+}
+
+// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
+// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
+bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
+{
+ const int MAX_LOOP_ITERATIONS = 254;
+ TInfoSinkBase &out = mBody;
+
+ // Parse loops of the form:
+ // for(int index = initial; index [comparator] limit; index += increment)
+ TIntermSymbol *index = NULL;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+ if (init)
+ {
+ TIntermSequence &sequence = init->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && variable->getQualifier() == EvqTemporary)
+ {
+ TIntermBinary *assign = variable->getAsBinaryNode();
+
+ if (assign->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+ TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+ if (symbol && constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ index = symbol;
+ initial = constant->getIConst(0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Parse comparator and limit value
+ if (index != NULL && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ comparator = test->getOp();
+ limit = constant->getIConst(0);
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != NULL && comparator != EOpNull && node->getExpression())
+ {
+ TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+ TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+ if (binaryTerminal)
+ {
+ TOperator op = binaryTerminal->getOp();
+ TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->isScalar())
+ {
+ int value = constant->getIConst(0);
+
+ switch (op)
+ {
+ case EOpAddAssign: increment = value; break;
+ case EOpSubAssign: increment = -value; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+ }
+ else if (unaryTerminal)
+ {
+ TOperator op = unaryTerminal->getOp();
+
+ switch (op)
+ {
+ case EOpPostIncrement: increment = 1; break;
+ case EOpPostDecrement: increment = -1; break;
+ case EOpPreIncrement: increment = 1; break;
+ case EOpPreDecrement: increment = -1; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+
+ if (index != NULL && comparator != EOpNull && increment != 0)
+ {
+ if (comparator == EOpLessThanEqual)
+ {
+ comparator = EOpLessThan;
+ limit += 1;
+ }
+
+ if (comparator == EOpLessThan)
+ {
+ int iterations = (limit - initial) / increment;
+
+ if (iterations <= MAX_LOOP_ITERATIONS)
+ {
+ return false; // Not an excessive loop
+ }
+
+ TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
+ mExcessiveLoopIndex = index;
+
+ out << "{int ";
+ index->traverse(this);
+ out << ";\n"
+ "bool Break";
+ index->traverse(this);
+ out << " = false;\n";
+
+ bool firstLoopFragment = true;
+
+ while (iterations > 0)
+ {
+ int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
+
+ if (!firstLoopFragment)
+ {
+ out << "if (!Break";
+ index->traverse(this);
+ out << ") {\n";
+ }
+
+ if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
+ {
+ mExcessiveLoopIndex = NULL; // Stops setting the Break flag
+ }
+
+ // for(int index = initial; index < clampedLimit; index += increment)
+
+ out << "for(";
+ index->traverse(this);
+ out << " = ";
+ out << initial;
+
+ out << "; ";
+ index->traverse(this);
+ out << " < ";
+ out << clampedLimit;
+
+ out << "; ";
+ index->traverse(this);
+ out << " += ";
+ out << increment;
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";}\n";
+
+ if (!firstLoopFragment)
+ {
+ out << "}\n";
+ }
+
+ firstLoopFragment = false;
+
+ initial += MAX_LOOP_ITERATIONS * increment;
+ iterations -= MAX_LOOP_ITERATIONS;
+ }
+
+ out << "}";
+
+ mExcessiveLoopIndex = restoreIndex;
+
+ return true;
+ }
+ else UNIMPLEMENTED();
+ }
+
+ return false; // Not handled as an excessive loop
+}
+
+void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (visit == PreVisit)
+ {
+ out << preString;
+ }
+ else if (visit == InVisit)
+ {
+ out << inString;
+ }
+ else if (visit == PostVisit)
+ {
+ out << postString;
+ }
+}
+
+void OutputHLSL::outputLineDirective(int line)
+{
+ if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
+ {
+ mBody << "\n";
+ mBody << "#line " << line;
+
+ if (mContext.sourcePath)
+ {
+ mBody << " \"" << mContext.sourcePath << "\"";
+ }
+
+ mBody << "\n";
+ }
+}
+
+TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
+{
+ TQualifier qualifier = symbol->getQualifier();
+ const TType &type = symbol->getType();
+ TString name = symbol->getSymbol();
+
+ if (name.empty()) // HLSL demands named arguments, also for prototypes
+ {
+ name = "x" + str(mUniqueIndex++);
+ }
+ else
+ {
+ name = decorate(name);
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " +
+ qualifierString(qualifier) + " " + samplerString(type) + " sampler_" + name + arrayString(type);
+ }
+
+ return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
+}
+
+TString OutputHLSL::interpolationString(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqVaryingIn: return "";
+ case EvqFragmentIn: return "";
+ case EvqInvariantVaryingIn: return "";
+ case EvqSmoothIn: return "linear";
+ case EvqFlatIn: return "nointerpolation";
+ case EvqCentroidIn: return "centroid";
+ case EvqVaryingOut: return "";
+ case EvqVertexOut: return "";
+ case EvqInvariantVaryingOut: return "";
+ case EvqSmoothOut: return "linear";
+ case EvqFlatOut: return "nointerpolation";
+ case EvqCentroidOut: return "centroid";
+ default: UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString OutputHLSL::qualifierString(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqIn: return "in";
+ case EvqOut: return "inout"; // 'out' results in an HLSL error if not all fields are written, for GLSL it's undefined
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ default: UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString OutputHLSL::typeString(const TType &type)
+{
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ const TString& typeName = structure->name();
+ if (typeName != "")
+ {
+ return structNameString(*type.getStruct());
+ }
+ else // Nameless structure, define in place
+ {
+ return structureString(*structure, false, false);
+ }
+ }
+ else if (type.isMatrix())
+ {
+ int cols = type.getCols();
+ int rows = type.getRows();
+ return "float" + str(cols) + "x" + str(rows);
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1: return "float";
+ case 2: return "float2";
+ case 3: return "float3";
+ case 4: return "float4";
+ }
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1: return "int";
+ case 2: return "int2";
+ case 3: return "int3";
+ case 4: return "int4";
+ }
+ case EbtUInt:
+ switch (type.getNominalSize())
+ {
+ case 1: return "uint";
+ case 2: return "uint2";
+ case 3: return "uint3";
+ case 4: return "uint4";
+ }
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1: return "bool";
+ case 2: return "bool2";
+ case 3: return "bool3";
+ case 4: return "bool4";
+ }
+ case EbtVoid:
+ return "void";
+ case EbtSampler2D:
+ case EbtISampler2D:
+ case EbtUSampler2D:
+ case EbtSampler2DArray:
+ case EbtISampler2DArray:
+ case EbtUSampler2DArray:
+ return "sampler2D";
+ case EbtSamplerCube:
+ case EbtISamplerCube:
+ case EbtUSamplerCube:
+ return "samplerCUBE";
+ case EbtSamplerExternalOES:
+ return "sampler2D";
+ default:
+ break;
+ }
+ }
+
+ UNREACHABLE();
+ return "<unknown type>";
+}
+
+TString OutputHLSL::textureString(const TType &type)
+{
+ switch (type.getBasicType())
+ {
+ case EbtSampler2D: return "Texture2D";
+ case EbtSamplerCube: return "TextureCube";
+ case EbtSamplerExternalOES: return "Texture2D";
+ case EbtSampler2DArray: return "Texture2DArray";
+ case EbtSampler3D: return "Texture3D";
+ case EbtISampler2D: return "Texture2D<int4>";
+ case EbtISampler3D: return "Texture3D<int4>";
+ case EbtISamplerCube: return "Texture2DArray<int4>";
+ case EbtISampler2DArray: return "Texture2DArray<int4>";
+ case EbtUSampler2D: return "Texture2D<uint4>";
+ case EbtUSampler3D: return "Texture3D<uint4>";
+ case EbtUSamplerCube: return "Texture2DArray<uint4>";
+ case EbtUSampler2DArray: return "Texture2DArray<uint4>";
+ case EbtSampler2DShadow: return "Texture2D";
+ case EbtSamplerCubeShadow: return "TextureCube";
+ case EbtSampler2DArrayShadow: return "Texture2DArray";
+ default: UNREACHABLE();
+ }
+
+ return "<unknown texture type>";
+}
+
+TString OutputHLSL::samplerString(const TType &type)
+{
+ if (IsShadowSampler(type.getBasicType()))
+ {
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+TString OutputHLSL::arrayString(const TType &type)
+{
+ if (!type.isArray())
+ {
+ return "";
+ }
+
+ return "[" + str(type.getArraySize()) + "]";
+}
+
+TString OutputHLSL::initializer(const TType &type)
+{
+ TString string;
+
+ size_t size = type.getObjectSize();
+ for (size_t component = 0; component < size; component++)
+ {
+ string += "0";
+
+ if (component + 1 < size)
+ {
+ string += ", ";
+ }
+ }
+
+ return "{" + string + "}";
+}
+
+TString OutputHLSL::structureString(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
+{
+ const TFieldList &fields = structure.fields();
+ const bool isNameless = (structure.name() == "");
+ const TString &structName = structureTypeName(structure, useHLSLRowMajorPacking, useStd140Packing);
+ const TString declareString = (isNameless ? "struct" : "struct " + structName);
+
+ TString string;
+ string += declareString + "\n"
+ "{\n";
+
+ int elementIndex = 0;
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TField &field = *fields[i];
+ const TType &fieldType = *field.type();
+ const TStructure *fieldStruct = fieldType.getStruct();
+ const TString &fieldTypeString = fieldStruct ? structureTypeName(*fieldStruct, useHLSLRowMajorPacking, useStd140Packing) : typeString(fieldType);
+
+ if (useStd140Packing)
+ {
+ string += std140PrePaddingString(*field.type(), &elementIndex);
+ }
+
+ string += " " + fieldTypeString + " " + decorateField(field.name(), structure) + arrayString(fieldType) + ";\n";
+
+ if (useStd140Packing)
+ {
+ string += std140PostPaddingString(*field.type(), useHLSLRowMajorPacking);
+ }
+ }
+
+ // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
+ string += (isNameless ? "} " : "};\n");
+
+ // Add remaining element index to the global map, for use with nested structs in standard layouts
+ if (useStd140Packing)
+ {
+ mStd140StructElementIndexes[structName] = elementIndex;
+ }
+
+ return string;
+}
+
+TString OutputHLSL::structureTypeName(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
+{
+ if (structure.name() == "")
+ {
+ return "";
+ }
+
+ TString prefix = "";
+
+ // Structs packed with row-major matrices in HLSL are prefixed with "rm"
+ // GLSL column-major maps to HLSL row-major, and the converse is true
+
+ if (useStd140Packing)
+ {
+ prefix += "std";
+ }
+
+ if (useHLSLRowMajorPacking)
+ {
+ if (prefix != "") prefix += "_";
+ prefix += "rm";
+ }
+
+ return prefix + structNameString(structure);
+}
+
+void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
+{
+ if (name == "")
+ {
+ return; // Nameless structures don't have constructors
+ }
+
+ if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
+ {
+ return; // Already added
+ }
+
+ TType ctorType = type;
+ ctorType.clearArrayness();
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ typedef std::vector<TType> ParameterArray;
+ ParameterArray ctorParameters;
+
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ mStructNames.insert(name);
+
+ const TString &structString = structureString(*structure, false, false);
+
+ if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
+ {
+ // Add row-major packed struct for interface blocks
+ TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
+ structureString(*structure, true, false) +
+ "#pragma pack_matrix(column_major)\n";
+
+ TString std140String = structureString(*structure, false, true);
+ TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
+ structureString(*structure, true, true) +
+ "#pragma pack_matrix(column_major)\n";
+
+ mStructDeclarations.push_back(structString);
+ mStructDeclarations.push_back(rowMajorString);
+ mStructDeclarations.push_back(std140String);
+ mStructDeclarations.push_back(std140RowMajorString);
+ }
+
+ const TFieldList &fields = structure->fields();
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ ctorParameters.push_back(*fields[i]->type());
+ }
+ }
+ else if (parameters)
+ {
+ for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
+ {
+ ctorParameters.push_back((*parameter)->getAsTyped()->getType());
+ }
+ }
+ else UNREACHABLE();
+
+ TString constructor;
+
+ if (ctorType.getStruct())
+ {
+ constructor += name + " " + name + "_ctor(";
+ }
+ else // Built-in type
+ {
+ constructor += typeString(ctorType) + " " + name + "(";
+ }
+
+ for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+ {
+ const TType &type = ctorParameters[parameter];
+
+ constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
+
+ if (parameter < ctorParameters.size() - 1)
+ {
+ constructor += ", ";
+ }
+ }
+
+ constructor += ")\n"
+ "{\n";
+
+ if (ctorType.getStruct())
+ {
+ constructor += " " + name + " structure = {";
+ }
+ else
+ {
+ constructor += " return " + typeString(ctorType) + "(";
+ }
+
+ if (ctorType.isMatrix() && ctorParameters.size() == 1)
+ {
+ int rows = ctorType.getRows();
+ int cols = ctorType.getCols();
+ const TType &parameter = ctorParameters[0];
+
+ if (parameter.isScalar())
+ {
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ constructor += TString((row == col) ? "x0" : "0.0");
+
+ if (row < rows - 1 || col < cols - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else if (parameter.isMatrix())
+ {
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ if (row < parameter.getRows() && col < parameter.getCols())
+ {
+ constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
+ }
+ else
+ {
+ constructor += TString((row == col) ? "1.0" : "0.0");
+ }
+
+ if (row < rows - 1 || col < cols - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+ else
+ {
+ size_t remainingComponents = ctorType.getObjectSize();
+ size_t parameterIndex = 0;
+
+ while (remainingComponents > 0)
+ {
+ const TType &parameter = ctorParameters[parameterIndex];
+ const size_t parameterSize = parameter.getObjectSize();
+ bool moreParameters = parameterIndex + 1 < ctorParameters.size();
+
+ constructor += "x" + str(parameterIndex);
+
+ if (parameter.isScalar())
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (parameter.isVector())
+ {
+ if (remainingComponents == parameterSize || moreParameters)
+ {
+ ASSERT(parameterSize <= remainingComponents);
+ remainingComponents -= parameterSize;
+ }
+ else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
+ {
+ switch (remainingComponents)
+ {
+ case 1: constructor += ".x"; break;
+ case 2: constructor += ".xy"; break;
+ case 3: constructor += ".xyz"; break;
+ case 4: constructor += ".xyzw"; break;
+ default: UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else UNREACHABLE();
+ }
+ else if (parameter.isMatrix() || parameter.getStruct())
+ {
+ ASSERT(remainingComponents == parameterSize || moreParameters);
+ ASSERT(parameterSize <= remainingComponents);
+
+ remainingComponents -= parameterSize;
+ }
+ else UNREACHABLE();
+
+ if (moreParameters)
+ {
+ parameterIndex++;
+ }
+
+ if (remainingComponents)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+
+ if (ctorType.getStruct())
+ {
+ constructor += "};\n"
+ " return structure;\n"
+ "}\n";
+ }
+ else
+ {
+ constructor += ");\n"
+ "}\n";
+ }
+
+ mConstructors.insert(constructor);
+}
+
+const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
+{
+ TInfoSinkBase &out = mBody;
+
+ const TStructure* structure = type.getStruct();
+ if (structure)
+ {
+ out << structNameString(*structure) + "_ctor(";
+
+ const TFieldList& fields = structure->fields();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TType *fieldType = fields[i]->type();
+
+ constUnion = writeConstantUnion(*fieldType, constUnion);
+
+ if (i != fields.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+
+ if (writeType)
+ {
+ out << typeString(type) << "(";
+ }
+
+ for (size_t i = 0; i < size; i++, constUnion++)
+ {
+ switch (constUnion->getType())
+ {
+ case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
+ case EbtInt: out << constUnion->getIConst(); break;
+ case EbtUInt: out << constUnion->getUConst(); break;
+ case EbtBool: out << constUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ if (writeType)
+ {
+ out << ")";
+ }
+ }
+
+ return constUnion;
+}
+
+TString OutputHLSL::structNameString(const TStructure &structure)
+{
+ if (structure.name().empty())
+ {
+ return "";
+ }
+
+ return "ss_" + str(structure.uniqueId()) + structure.name();
+}
+
+TString OutputHLSL::decorate(const TString &string)
+{
+ if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
+ {
+ return "_" + string;
+ }
+
+ return string;
+}
+
+TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
+{
+ if (type.getBasicType() == EbtSamplerExternalOES)
+ {
+ return "ex_" + string;
+ }
+
+ return decorate(string);
+}
+
+TString OutputHLSL::decorateField(const TString &string, const TStructure &structure)
+{
+ if (structure.name().compare(0, 3, "gl_") != 0)
+ {
+ return decorate(string);
+ }
+
+ return string;
+}
+
+void OutputHLSL::declareInterfaceBlockField(const TType &type, const TString &name, std::vector<gl::InterfaceBlockField>& output)
+{
+ const TStructure *structure = type.getStruct();
+
+ if (!structure)
+ {
+ const bool isRowMajorMatrix = (type.isMatrix() && type.getLayoutQualifier().matrixPacking == EmpRowMajor);
+ gl::InterfaceBlockField field(glVariableType(type), glVariablePrecision(type), name.c_str(),
+ (unsigned int)type.getArraySize(), isRowMajorMatrix);
+ output.push_back(field);
+ }
+ else
+ {
+ gl::InterfaceBlockField structField(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), false);
+
+ const TFieldList &fields = structure->fields();
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ TField *field = fields[fieldIndex];
+ TType *fieldType = field->type();
+
+ // make sure to copy matrix packing information
+ fieldType->setLayoutQualifier(type.getLayoutQualifier());
+
+ declareInterfaceBlockField(*fieldType, field->name(), structField.fields);
+ }
+
+ output.push_back(structField);
+ }
+}
+
+gl::Uniform OutputHLSL::declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<gl::Uniform>& output)
+{
+ const TStructure *structure = type.getStruct();
+
+ if (!structure)
+ {
+ gl::Uniform uniform(glVariableType(type), glVariablePrecision(type), name.c_str(),
+ (unsigned int)type.getArraySize(), (unsigned int)registerIndex, 0);
+ output.push_back(uniform);
+
+ return uniform;
+ }
+ else
+ {
+ gl::Uniform structUniform(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(),
+ (unsigned int)registerIndex, GL_INVALID_INDEX);
+
+ const TFieldList &fields = structure->fields();
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ TField *field = fields[fieldIndex];
+ TType *fieldType = field->type();
+
+ declareUniformToList(*fieldType, field->name(), GL_INVALID_INDEX, structUniform.fields);
+ }
+
+ // assign register offset information -- this will override the information in any sub-structures.
+ HLSLVariableGetRegisterInfo(registerIndex, &structUniform, mOutputType);
+
+ output.push_back(structUniform);
+
+ return structUniform;
+ }
+}
+
+gl::InterpolationType getInterpolationType(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqFlatIn:
+ case EvqFlatOut:
+ return gl::INTERPOLATION_FLAT;
+
+ case EvqSmoothIn:
+ case EvqSmoothOut:
+ case EvqVertexOut:
+ case EvqFragmentIn:
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ return gl::INTERPOLATION_SMOOTH;
+
+ case EvqCentroidIn:
+ case EvqCentroidOut:
+ return gl::INTERPOLATION_CENTROID;
+
+ default: UNREACHABLE();
+ return gl::INTERPOLATION_SMOOTH;
+ }
+}
+
+void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<gl::Varying>& fieldsOut)
+{
+ const TStructure *structure = type.getStruct();
+
+ gl::InterpolationType interpolation = getInterpolationType(baseTypeQualifier);
+ if (!structure)
+ {
+ gl::Varying varying(glVariableType(type), glVariablePrecision(type), name.c_str(), (unsigned int)type.getArraySize(), interpolation);
+ fieldsOut.push_back(varying);
+ }
+ else
+ {
+ gl::Varying structVarying(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), interpolation);
+ const TFieldList &fields = structure->fields();
+
+ structVarying.structName = structure->name().c_str();
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
+ {
+ const TField &field = *fields[fieldIndex];
+ declareVaryingToList(*field.type(), baseTypeQualifier, field.name(), structVarying.fields);
+ }
+
+ fieldsOut.push_back(structVarying);
+ }
+}
+
+int OutputHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
+{
+ int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
+
+ const gl::Uniform &uniform = declareUniformToList(type, name, registerIndex, mActiveUniforms);
+
+ if (IsSampler(type.getBasicType()))
+ {
+ mSamplerRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType);
+ }
+ else
+ {
+ mUniformRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType);
+ }
+
+ return registerIndex;
+}
+
+GLenum OutputHLSL::glVariableType(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ if (type.isScalar())
+ {
+ return GL_FLOAT;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_FLOAT_VEC2;
+ case 3: return GL_FLOAT_VEC3;
+ case 4: return GL_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch (type.getCols())
+ {
+ case 2:
+ switch(type.getRows())
+ {
+ case 2: return GL_FLOAT_MAT2;
+ case 3: return GL_FLOAT_MAT2x3;
+ case 4: return GL_FLOAT_MAT2x4;
+ default: UNREACHABLE();
+ }
+
+ case 3:
+ switch(type.getRows())
+ {
+ case 2: return GL_FLOAT_MAT3x2;
+ case 3: return GL_FLOAT_MAT3;
+ case 4: return GL_FLOAT_MAT3x4;
+ default: UNREACHABLE();
+ }
+
+ case 4:
+ switch(type.getRows())
+ {
+ case 2: return GL_FLOAT_MAT4x2;
+ case 3: return GL_FLOAT_MAT4x3;
+ case 4: return GL_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtInt)
+ {
+ if (type.isScalar())
+ {
+ return GL_INT;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_INT_VEC2;
+ case 3: return GL_INT_VEC3;
+ case 4: return GL_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtUInt)
+ {
+ if (type.isScalar())
+ {
+ return GL_UNSIGNED_INT;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_UNSIGNED_INT_VEC2;
+ case 3: return GL_UNSIGNED_INT_VEC3;
+ case 4: return GL_UNSIGNED_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtBool)
+ {
+ if (type.isScalar())
+ {
+ return GL_BOOL;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_BOOL_VEC2;
+ case 3: return GL_BOOL_VEC3;
+ case 4: return GL_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ switch(type.getBasicType())
+ {
+ case EbtSampler2D: return GL_SAMPLER_2D;
+ case EbtSampler3D: return GL_SAMPLER_3D;
+ case EbtSamplerCube: return GL_SAMPLER_CUBE;
+ case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY;
+ case EbtISampler2D: return GL_INT_SAMPLER_2D;
+ case EbtISampler3D: return GL_INT_SAMPLER_3D;
+ case EbtISamplerCube: return GL_INT_SAMPLER_CUBE;
+ case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY;
+ case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D;
+ case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D;
+ case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE;
+ case EbtUSampler2DArray: return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
+ case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW;
+ case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW;
+ case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW;
+ default: UNREACHABLE();
+ }
+
+ return GL_NONE;
+}
+
+GLenum OutputHLSL::glVariablePrecision(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh: return GL_HIGH_FLOAT;
+ case EbpMedium: return GL_MEDIUM_FLOAT;
+ case EbpLow: return GL_LOW_FLOAT;
+ case EbpUndefined:
+ // Should be defined as the default precision by the parser
+ default: UNREACHABLE();
+ }
+ }
+ else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh: return GL_HIGH_INT;
+ case EbpMedium: return GL_MEDIUM_INT;
+ case EbpLow: return GL_LOW_INT;
+ case EbpUndefined:
+ // Should be defined as the default precision by the parser
+ default: UNREACHABLE();
+ }
+ }
+
+ // Other types (boolean, sampler) don't have a precision
+ return GL_NONE;
+}
+
+bool OutputHLSL::isVaryingOut(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqVaryingOut:
+ case EvqInvariantVaryingOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqVertexOut:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+}
+
+bool OutputHLSL::isVaryingIn(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqInvariantVaryingIn:
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqCentroidIn:
+ case EvqFragmentIn:
+ return true;
+
+ default: break;
+ }
+
+ return false;
+}
+
+bool OutputHLSL::isVarying(TQualifier qualifier)
+{
+ return isVaryingIn(qualifier) || isVaryingOut(qualifier);
+}
+
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h
new file mode 100644
index 00000000000..ab5a90be6e6
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h
@@ -0,0 +1,220 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_OUTPUTHLSL_H_
+#define COMPILER_OUTPUTHLSL_H_
+
+#include <list>
+#include <set>
+#include <map>
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2.h>
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/ParseContext.h"
+#include "common/shadervars.h"
+
+namespace sh
+{
+class UnfoldShortCircuit;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType);
+ ~OutputHLSL();
+
+ void output();
+
+ TInfoSinkBase &getBodyStream();
+ const std::vector<gl::Uniform> &getUniforms();
+ const std::vector<gl::InterfaceBlock> &getInterfaceBlocks() const;
+ const std::vector<gl::Attribute> &getOutputVariables() const;
+ const std::vector<gl::Attribute> &getAttributes() const;
+ const std::vector<gl::Varying> &getVaryings() const;
+
+ TString typeString(const TType &type);
+ TString textureString(const TType &type);
+ TString samplerString(const TType &type);
+ TString interpolationString(TQualifier qualifier);
+ TString structureString(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
+ TString structureTypeName(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
+ static TString qualifierString(TQualifier qualifier);
+ static TString arrayString(const TType &type);
+ static TString initializer(const TType &type);
+ static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes
+ static TString decorateUniform(const TString &string, const TType &type);
+ static TString decorateField(const TString &string, const TStructure &structure);
+
+ protected:
+ void header();
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol*);
+ void visitRaw(TIntermRaw*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ void traverseStatements(TIntermNode *node);
+ bool isSingleStatement(TIntermNode *node);
+ bool handleExcessiveLoop(TIntermLoop *node);
+ void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString);
+ void outputLineDirective(int line);
+ TString argumentString(const TIntermSymbol *symbol);
+ int vectorSize(const TType &type) const;
+
+ void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
+ const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+
+ TString structNameString(const TStructure &structure);
+
+ TParseContext &mContext;
+ const ShShaderOutput mOutputType;
+ UnfoldShortCircuit *mUnfoldShortCircuit;
+ bool mInsideFunction;
+
+ // Output streams
+ TInfoSinkBase mHeader;
+ TInfoSinkBase mBody;
+ TInfoSinkBase mFooter;
+
+ typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
+ ReferencedSymbols mReferencedUniforms;
+ ReferencedSymbols mReferencedInterfaceBlocks;
+ ReferencedSymbols mReferencedAttributes;
+ ReferencedSymbols mReferencedVaryings;
+ ReferencedSymbols mReferencedOutputVariables;
+
+ struct TextureFunction
+ {
+ enum Method
+ {
+ IMPLICIT, // Mipmap LOD determined implicitly (standard lookup)
+ BIAS,
+ LOD,
+ LOD0,
+ LOD0BIAS,
+ SIZE, // textureSize()
+ FETCH,
+ GRAD
+ };
+
+ TBasicType sampler;
+ int coords;
+ bool proj;
+ bool offset;
+ Method method;
+
+ TString name() const;
+
+ bool operator<(const TextureFunction &rhs) const;
+ };
+
+ typedef std::set<TextureFunction> TextureFunctionSet;
+
+ // Parameters determining what goes in the header output
+ TextureFunctionSet mUsesTexture;
+ bool mUsesFragColor;
+ bool mUsesFragData;
+ bool mUsesDepthRange;
+ bool mUsesFragCoord;
+ bool mUsesPointCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesFragDepth;
+ bool mUsesXor;
+ bool mUsesMod1;
+ bool mUsesMod2v;
+ bool mUsesMod2f;
+ bool mUsesMod3v;
+ bool mUsesMod3f;
+ bool mUsesMod4v;
+ bool mUsesMod4f;
+ bool mUsesFaceforward1;
+ bool mUsesFaceforward2;
+ bool mUsesFaceforward3;
+ bool mUsesFaceforward4;
+ bool mUsesAtan2_1;
+ bool mUsesAtan2_2;
+ bool mUsesAtan2_3;
+ bool mUsesAtan2_4;
+ bool mUsesDiscardRewriting;
+ bool mUsesNestedBreak;
+
+ int mNumRenderTargets;
+
+ typedef std::set<TString> Constructors;
+ Constructors mConstructors;
+
+ typedef std::set<TString> StructNames;
+ StructNames mStructNames;
+
+ typedef std::list<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ int mUniqueIndex; // For creating unique names
+
+ bool mContainsLoopDiscontinuity;
+ bool mOutputLod0Function;
+ bool mInsideDiscontinuousLoop;
+ int mNestedLoopDepth;
+
+ TIntermSymbol *mExcessiveLoopIndex;
+
+ int mUniformRegister;
+ int mInterfaceBlockRegister;
+ int mSamplerRegister;
+ int mPaddingCounter;
+
+ TString registerString(TIntermSymbol *operand);
+ int samplerRegister(TIntermSymbol *sampler);
+ int uniformRegister(TIntermSymbol *uniform);
+ void declareInterfaceBlockField(const TType &type, const TString &name, std::vector<gl::InterfaceBlockField>& output);
+ gl::Uniform declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<gl::Uniform>& output);
+ void declareUniform(const TType &type, const TString &name, int index);
+ void declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<gl::Varying>& fieldsOut);
+
+ // Returns the uniform's register index
+ int declareUniformAndAssignRegister(const TType &type, const TString &name);
+
+ TString interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field);
+ TString decoratePrivate(const TString &privateText);
+ TString interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlockType);
+ TString interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex);
+ TString interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage);
+ TString interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage);
+ TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock);
+ TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex);
+ TString std140PrePaddingString(const TType &type, int *elementIndex);
+ TString std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking);
+ TString structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName);
+
+ static GLenum glVariableType(const TType &type);
+ static GLenum glVariablePrecision(const TType &type);
+ static bool isVaryingIn(TQualifier qualifier);
+ static bool isVaryingOut(TQualifier qualifier);
+ static bool isVarying(TQualifier qualifier);
+
+ std::vector<gl::Uniform> mActiveUniforms;
+ std::vector<gl::InterfaceBlock> mActiveInterfaceBlocks;
+ std::vector<gl::Attribute> mActiveOutputVariables;
+ std::vector<gl::Attribute> mActiveAttributes;
+ std::vector<gl::Varying> mActiveVaryings;
+ std::map<TString, int> mStd140StructElementIndexes;
+ std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
+ std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
+
+ void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
+};
+}
+
+#endif // COMPILER_OUTPUTHLSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp
new file mode 100644
index 00000000000..f9009668b02
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp
@@ -0,0 +1,2649 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ParseContext.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/translator/glslang.h"
+#include "compiler/preprocessor/SourceLocation.h"
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a vector.
+//
+bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
+{
+ fields.num = (int) compString.size();
+ if (fields.num > 4) {
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+
+ enum {
+ exyzw,
+ ergba,
+ estpq
+ } fieldSet[4];
+
+ for (int i = 0; i < fields.num; ++i) {
+ switch (compString[i]) {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+ }
+
+ for (int i = 0; i < fields.num; ++i) {
+ if (fields.offsets[i] >= vecSize) {
+ error(line, "vector field selection out of range", compString.c_str());
+ return false;
+ }
+
+ if (i > 0) {
+ if (fieldSet[i] != fieldSet[i-1]) {
+ error(line, "illegal - vector component fields not from the same set", compString.c_str());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a matrix.
+//
+bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line)
+{
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = -1;
+ fields.col = -1;
+
+ if (compString.size() != 2) {
+ error(line, "illegal length of matrix field selection", compString.c_str());
+ return false;
+ }
+
+ if (compString[0] == '_') {
+ if (compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeCol = true;
+ fields.col = compString[1] - '0';
+ } else if (compString[1] == '_') {
+ if (compString[0] < '0' || compString[0] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeRow = true;
+ fields.row = compString[0] - '0';
+ } else {
+ if (compString[0] < '0' || compString[0] > '3' ||
+ compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.row = compString[0] - '0';
+ fields.col = compString[1] - '0';
+ }
+
+ if (fields.row >= matRows || fields.col >= matCols) {
+ error(line, "matrix field selection out of range", compString.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Errors
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Track whether errors have occurred.
+//
+void TParseContext::recover()
+{
+}
+
+//
+// Used by flex/bison to output all syntax and parsing errors.
+//
+void TParseContext::error(const TSourceLoc& loc,
+ const char* reason, const char* token,
+ const char* extraInfo)
+{
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ diagnostics.writeInfo(pp::Diagnostics::PP_ERROR,
+ srcLoc, reason, token, extraInfo);
+
+}
+
+void TParseContext::warning(const TSourceLoc& loc,
+ const char* reason, const char* token,
+ const char* extraInfo) {
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ diagnostics.writeInfo(pp::Diagnostics::PP_WARNING,
+ srcLoc, reason, token, extraInfo);
+}
+
+void TParseContext::trace(const char* str)
+{
+ diagnostics.writeDebug(str);
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
+ << " (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand type", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
+ << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand types ", op, extraInfo.c_str());
+}
+
+bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
+ if (!checksPrecisionErrors)
+ return false;
+ switch( type ){
+ case EbtFloat:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified for (float)", "" );
+ return true;
+ }
+ break;
+ case EbtInt:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified (int)", "" );
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+//
+// Both test and if necessary, spit out an error, to see if the node is really
+// an l-value that can be operated on this way.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
+{
+ TIntermSymbol* symNode = node->getAsSymbolNode();
+ TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode) {
+ bool errorReturn;
+
+ switch(binaryNode->getOp()) {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ return lValueErrorCheck(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
+ if (!errorReturn) {
+ int offset[4] = {0,0,0,0};
+
+ TIntermTyped* rightNode = binaryNode->getRight();
+ TIntermAggregate *aggrNode = rightNode->getAsAggregate();
+
+ for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
+ p != aggrNode->getSequence().end(); p++) {
+ int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
+ offset[value]++;
+ if (offset[value] > 1) {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+
+ return true;
+ }
+ }
+ }
+
+ return errorReturn;
+ default:
+ break;
+ }
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ const char* symbol = 0;
+ if (symNode != 0)
+ symbol = symNode->getSymbol().c_str();
+
+ const char* message = 0;
+ switch (node->getQualifier()) {
+ case EvqConst: message = "can't modify a const"; break;
+ case EvqConstReadOnly: message = "can't modify a const"; break;
+ case EvqAttribute: message = "can't modify an attribute"; break;
+ case EvqFragmentIn: message = "can't modify an input"; break;
+ case EvqVertexIn: message = "can't modify an input"; break;
+ case EvqUniform: message = "can't modify a uniform"; break;
+ case EvqVaryingIn: message = "can't modify a varying"; break;
+ case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
+ case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
+ case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
+ default:
+
+ //
+ // Type that can't be written to?
+ //
+ if (node->getBasicType() == EbtVoid) {
+ message = "can't modify void";
+ }
+ if (IsSampler(node->getBasicType())) {
+ message = "can't modify a sampler";
+ }
+ }
+
+ if (message == 0 && binaryNode == 0 && symNode == 0) {
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ //
+ // Everything else is okay, no error.
+ //
+ if (message == 0)
+ return false;
+
+ //
+ // If we get here, we have an error and a message.
+ //
+ if (symNode) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "\"" << symbol << "\" (" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+ else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "(" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::constErrorCheck(TIntermTyped* node)
+{
+ if (node->getQualifier() == EvqConst)
+ return false;
+
+ error(node->getLine(), "constant expression required", "");
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
+{
+ if (node->isScalarInt())
+ return false;
+
+ error(node->getLine(), "integer expression required", token);
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
+{
+ if (global)
+ return false;
+
+ error(line, "only allowed at global scope", token);
+
+ return true;
+}
+
+//
+// For now, keep it simple: if it starts "gl_", it's reserved, independent
+// of scope. Except, if the symbol table is at the built-in push-level,
+// which is when we are parsing built-ins.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
+// webgl shader.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
+{
+ static const char* reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel()) {
+ if (identifier.compare(0, 3, "gl_") == 0) {
+ error(line, reservedErrMsg, "gl_");
+ return true;
+ }
+ if (IsWebGLBasedSpec(shaderSpec)) {
+ if (identifier.compare(0, 6, "webgl_") == 0) {
+ error(line, reservedErrMsg, "webgl_");
+ return true;
+ }
+ if (identifier.compare(0, 7, "_webgl_") == 0) {
+ error(line, reservedErrMsg, "_webgl_");
+ return true;
+ }
+ if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
+ error(line, reservedErrMsg, "css_");
+ return true;
+ }
+ }
+ if (identifier.find("__") != TString::npos) {
+ error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Make sure there is enough data provided to the constructor to build
+// something of the type of the constructor. Also returns the type of
+// the constructor.
+//
+// Returns true if there was an error in construction.
+//
+bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
+{
+ *type = function.getReturnType();
+
+ bool constructingMatrix = false;
+ switch(op) {
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Note: It's okay to have too many components available, but not okay to have unused
+ // arguments. 'full' will go to true when enough args have been seen. If we loop
+ // again, there is an extra argument, so 'overfull' will become true.
+ //
+
+ size_t size = 0;
+ bool constType = true;
+ bool full = false;
+ bool overFull = false;
+ bool matrixInMatrix = false;
+ bool arrayArg = false;
+ for (size_t i = 0; i < function.getParamCount(); ++i) {
+ const TParameter& param = function.getParam(i);
+ size += param.type->getObjectSize();
+
+ if (constructingMatrix && param.type->isMatrix())
+ matrixInMatrix = true;
+ if (full)
+ overFull = true;
+ if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
+ full = true;
+ if (param.type->getQualifier() != EvqConst)
+ constType = false;
+ if (param.type->isArray())
+ arrayArg = true;
+ }
+
+ if (constType)
+ type->setQualifier(EvqConst);
+
+ if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return true;
+ }
+
+ if (arrayArg && op != EOpConstructStruct) {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return true;
+ }
+
+ if (matrixInMatrix && !type->isArray()) {
+ if (function.getParamCount() != 1) {
+ error(line, "constructing matrix from matrix can only take one argument", "constructor");
+ return true;
+ }
+ }
+
+ if (overFull) {
+ error(line, "too many arguments", "constructor");
+ return true;
+ }
+
+ if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) {
+ error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
+ return true;
+ }
+
+ if (!type->isMatrix() || !matrixInMatrix) {
+ if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
+ (op == EOpConstructStruct && size < type->getObjectSize())) {
+ error(line, "not enough data provided for construction", "constructor");
+ return true;
+ }
+ }
+
+ TIntermTyped *typed = node ? node->getAsTyped() : 0;
+ if (typed == 0) {
+ error(line, "constructor argument does not have a type", "constructor");
+ return true;
+ }
+ if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
+ error(line, "cannot convert a sampler", "constructor");
+ return true;
+ }
+ if (typed->getBasicType() == EbtVoid) {
+ error(line, "cannot convert a void", "constructor");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if a void variable has been declared and raise an error message for such a case
+//
+// returns true in case of an error
+//
+bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType)
+{
+ if (pubType.type == EbtVoid) {
+ error(line, "illegal use of type 'void'", identifier.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
+{
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+{
+ if (pType.type != EbtBool || pType.isAggregate()) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
+{
+ if (pType.type == EbtStruct) {
+ if (containsSampler(*pType.userDef)) {
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+
+ return true;
+ }
+
+ return false;
+ } else if (IsSampler(pType.type)) {
+ error(line, reason, getBasicString(pType.type));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+{
+ switch (pType.qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqAttribute:
+ case EvqVertexIn:
+ case EvqFragmentOut:
+ if (pType.type == EbtStruct)
+ {
+ error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
+ return true;
+ }
+
+ default: break;
+ }
+
+ if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
+{
+ if (pType.layoutQualifier.location != -1)
+ {
+ error(line, "location must only be specified for a single input or output variable", "location");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
+{
+ if ((qualifier == EvqOut || qualifier == EvqInOut) &&
+ type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
+ error(line, "samplers cannot be output parameters", type.getBasicString());
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::containsSampler(TType& type)
+{
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
+ const TFieldList& fields = type.getStruct()->fields();
+ for (unsigned int i = 0; i < fields.size(); ++i) {
+ if (containsSampler(*fields[i]->type()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Do size checking for an array type's size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
+{
+ TIntermConstantUnion* constant = expr->getAsConstantUnion();
+
+ if (constant == 0 || !constant->isScalarInt())
+ {
+ error(line, "array size must be a constant integer expression", "");
+ return true;
+ }
+
+ unsigned int unsignedSize = 0;
+
+ if (constant->getBasicType() == EbtUInt)
+ {
+ unsignedSize = constant->getUConst(0);
+ size = static_cast<int>(unsignedSize);
+ }
+ else
+ {
+ size = constant->getIConst(0);
+
+ if (size < 0)
+ {
+ error(line, "array size must be non-negative", "");
+ size = 1;
+ return true;
+ }
+
+ unsignedSize = static_cast<unsigned int>(size);
+ }
+
+ if (size == 0)
+ {
+ error(line, "array size must be greater than zero", "");
+ size = 1;
+ return true;
+ }
+
+ // The size of arrays is restricted here to prevent issues further down the
+ // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
+ // 4096 registers so this should be reasonable even for aggressively optimizable code.
+ const unsigned int sizeLimit = 65536;
+
+ if (unsignedSize > sizeLimit)
+ {
+ error(line, "array size too large", "");
+ size = 1;
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this qualifier can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type)
+{
+ if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConst)) {
+ error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this type can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
+{
+ //
+ // Can the type be an array?
+ //
+ if (type.array) {
+ error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do all the semantic checking for declaring an array, with and
+// without a size, and make the right changes to the symbol table.
+//
+// size == 0 means no specified size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable)
+{
+ //
+ // Don't check for reserved word use until after we know it's not in the symbol table,
+ // because reserved arrays can be redeclared.
+ //
+
+ bool builtIn = false;
+ bool sameScope = false;
+ TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope);
+ if (symbol == 0 || !sameScope) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+
+ if (! symbolTable.declare(*variable)) {
+ delete variable;
+ error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
+ return true;
+ }
+ } else {
+ if (! symbol->isVariable()) {
+ error(line, "variable expected", identifier.c_str());
+ return true;
+ }
+
+ variable = static_cast<TVariable*>(symbol);
+ if (! variable->getType().isArray()) {
+ error(line, "redeclaring non-array as array", identifier.c_str());
+ return true;
+ }
+ if (variable->getType().getArraySize() > 0) {
+ error(line, "redeclaration of array with size", identifier.c_str());
+ return true;
+ }
+
+ if (! variable->getType().sameElementType(TType(type))) {
+ error(line, "redeclaration of array with a different type", identifier.c_str());
+ return true;
+ }
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+//
+// Enforce non-initializer type/qualifier rules.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array)
+{
+ if (type.qualifier == EvqConst)
+ {
+ // Make the qualifier make sense.
+ type.qualifier = EvqTemporary;
+
+ if (array)
+ {
+ error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else if (type.isStructureContainingArrays())
+ {
+ error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else
+ {
+ error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do semantic checking for a variable declaration that has no initializer,
+// and update the symbol table.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable)
+{
+ if (reservedErrorCheck(line, identifier))
+ recover();
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (! symbolTable.declare(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ delete variable;
+ variable = 0;
+ return true;
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
+{
+ if (qualifier != EvqConst && qualifier != EvqTemporary) {
+ error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
+ return true;
+ }
+ if (qualifier == EvqConst && paramQualifier != EvqIn) {
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
+ return true;
+ }
+
+ if (qualifier == EvqConst)
+ type->setQualifier(EvqConstReadOnly);
+ else
+ type->setQualifier(paramQualifier);
+
+ return false;
+}
+
+bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
+{
+ const TExtensionBehavior& extBehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
+ if (iter == extBehavior.end()) {
+ error(line, "extension", extension.c_str(), "is not supported");
+ return true;
+ }
+ // In GLSL ES, an extension's default behavior is "disable".
+ if (iter->second == EBhDisable || iter->second == EBhUndefined) {
+ error(line, "extension", extension.c_str(), "is disabled");
+ return true;
+ }
+ if (iter->second == EBhWarn) {
+ warning(line, "extension", extension.c_str(), "is being used");
+ return false;
+ }
+
+ return false;
+}
+
+bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
+{
+ if (structQualifierErrorCheck(identifierLocation, publicType))
+ return true;
+
+ // check for layout qualifier issues
+ const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks");
+ return true;
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks");
+ return true;
+ }
+
+ if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier)
+{
+ if (layoutQualifier.location != -1)
+ {
+ error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::supportsExtension(const char* extension)
+{
+ const TExtensionBehavior& extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+ return (iter != extbehavior.end());
+}
+
+bool TParseContext::isExtensionEnabled(const char* extension) const
+{
+ const TExtensionBehavior& extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+
+ if (iter == extbehavior.end())
+ {
+ return false;
+ }
+
+ return (iter->second == EBhEnable || iter->second == EBhRequire);
+}
+
+void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior)
+{
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ directiveHandler.handleExtension(srcLoc, extName, behavior);
+}
+
+void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value)
+{
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ directiveHandler.handlePragma(srcLoc, name, value);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise 0.
+//
+const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn)
+{
+ // First find by unmangled name to check whether the function name has been
+ // hidden by a variable name or struct typename.
+ // If a function is found, check for one with a matching argument list.
+ const TSymbol* symbol = symbolTable.find(call->getName(), shaderVersion, builtIn);
+ if (symbol == 0 || symbol->isFunction()) {
+ symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn);
+ }
+
+ if (symbol == 0) {
+ error(line, "no matching overloaded function found", call->getName().c_str());
+ return 0;
+ }
+
+ if (!symbol->isFunction()) {
+ error(line, "function name expected", call->getName().c_str());
+ return 0;
+ }
+
+ return static_cast<const TFunction*>(symbol);
+}
+
+//
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
+{
+ TType type = TType(pType);
+
+ if (variable == 0) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ if (voidErrorCheck(line, identifier, pType))
+ return true;
+
+ //
+ // add variable to symbol table
+ //
+ variable = new TVariable(&identifier, type);
+ if (! symbolTable.declare(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ return true;
+ // don't delete variable, it's used by error recovery, and the pool
+ // pop will take care of the memory
+ }
+ }
+
+ //
+ // identifier must be of type constant, a global, or a temporary
+ //
+ TQualifier qualifier = variable->getType().getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
+ error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
+ return true;
+ }
+ //
+ // test for and propagate constant
+ //
+
+ if (qualifier == EvqConst) {
+ if (qualifier != initializer->getType().getQualifier()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " assigning non-constant to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (type != initializer->getType()) {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (initializer->getAsConstantUnion()) {
+ variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+ } else if (initializer->getAsSymbolNode()) {
+ const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
+ const TVariable* tVar = static_cast<const TVariable*>(symbol);
+
+ ConstantUnion* constArray = tVar->getConstPointer();
+ variable->shareConstPointer(constArray);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " cannot assign to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ }
+
+ if (qualifier != EvqConst) {
+ TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (intermNode == 0) {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
+ }
+ } else
+ intermNode = 0;
+
+ return false;
+}
+
+bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
+{
+ ASSERT(aggrNode != NULL);
+ if (!aggrNode->isConstructor())
+ return false;
+
+ bool allConstant = true;
+
+ // check if all the child nodes are constants so that they can be inserted into
+ // the parent node
+ TIntermSequence &sequence = aggrNode->getSequence() ;
+ for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
+ if (!(*p)->getAsTyped()->getAsConstantUnion())
+ return false;
+ }
+
+ return allConstant;
+}
+
+TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
+{
+ TPublicType returnType = typeSpecifier;
+ returnType.qualifier = qualifier;
+ returnType.layoutQualifier = layoutQualifier;
+
+ if (typeSpecifier.array)
+ {
+ error(typeSpecifier.line, "not supported", "first-class array");
+ recover();
+ returnType.setArray(false);
+ }
+
+ if (shaderVersion < 300)
+ {
+ if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
+ {
+ error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
+ recover();
+ }
+
+ if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
+ (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
+ {
+ error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
+ recover();
+ }
+ }
+ else
+ {
+ switch (qualifier)
+ {
+ case EvqSmoothIn:
+ case EvqSmoothOut:
+ case EvqVertexOut:
+ case EvqFragmentIn:
+ case EvqCentroidOut:
+ case EvqCentroidIn:
+ if (typeSpecifier.type == EbtBool)
+ {
+ error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
+ recover();
+ }
+ if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
+ {
+ error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
+ recover();
+ }
+ break;
+
+ case EvqVertexIn:
+ case EvqFragmentOut:
+ case EvqFlatIn:
+ case EvqFlatOut:
+ if (typeSpecifier.type == EbtBool)
+ {
+ error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
+ recover();
+ }
+ break;
+
+ default: break;
+ }
+ }
+
+ return returnType;
+}
+
+TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
+{
+ TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
+ TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
+
+ if (identifier != "")
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ recover();
+
+ // this error check can mutate the type
+ if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
+ recover();
+
+ TVariable* variable = 0;
+
+ if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
+ recover();
+
+ if (variable && symbol)
+ {
+ symbol->setId(variable->getUniqueId());
+ }
+ }
+
+ return aggregate;
+}
+
+TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression)
+{
+ if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ recover();
+
+ // this error check can mutate the type
+ if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
+ recover();
+
+ if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
+ {
+ recover();
+ }
+
+ TPublicType arrayType = publicType;
+
+ int size;
+ if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
+ {
+ recover();
+ }
+ else
+ {
+ arrayType.setArray(true, size);
+ }
+
+ TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(arrayType), identifierLocation);
+ TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
+ TVariable* variable = 0;
+
+ if (arrayErrorCheck(identifierLocation, identifier, arrayType, variable))
+ recover();
+
+ if (variable && symbol)
+ {
+ symbol->setId(variable->getUniqueId());
+ }
+
+ return aggregate;
+}
+
+TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
+{
+ if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ recover();
+
+ TIntermNode* intermNode;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
+ {
+ //
+ // Build intermediate representation
+ //
+ return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL;
+ }
+ else
+ {
+ recover();
+ return NULL;
+ }
+}
+
+TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
+{
+ if (publicType.type == EbtInvariant && !identifierSymbol)
+ {
+ error(identifierLocation, "undeclared identifier declared as invariant", identifier.c_str());
+ recover();
+ }
+
+ TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
+ TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
+
+ if (structQualifierErrorCheck(identifierLocation, publicType))
+ recover();
+
+ if (locationDeclaratorListCheck(identifierLocation, publicType))
+ recover();
+
+ if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
+ recover();
+
+ TVariable* variable = 0;
+ if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
+ recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+
+ return intermAggregate;
+}
+
+TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression)
+{
+ if (structQualifierErrorCheck(identifierLocation, publicType))
+ recover();
+
+ if (locationDeclaratorListCheck(identifierLocation, publicType))
+ recover();
+
+ if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
+ recover();
+
+ if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
+ {
+ recover();
+ }
+ else if (indexExpression)
+ {
+ int size;
+ if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
+ recover();
+ TPublicType arrayType(publicType);
+ arrayType.setArray(true, size);
+ TVariable* variable = NULL;
+ if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
+ recover();
+ TType type = TType(arrayType);
+ type.setArraySize(size);
+
+ return intermediate.growAggregate(declaratorList, intermediate.addSymbol(variable ? variable->getUniqueId() : 0, identifier, type, identifierLocation), identifierLocation);
+ }
+ else
+ {
+ TPublicType arrayType(publicType);
+ arrayType.setArray(true);
+ TVariable* variable = NULL;
+ if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
+ recover();
+ }
+
+ return NULL;
+}
+
+TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
+{
+ if (structQualifierErrorCheck(identifierLocation, publicType))
+ recover();
+
+ if (locationDeclaratorListCheck(identifierLocation, publicType))
+ recover();
+
+ TIntermNode* intermNode;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
+ {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ {
+ return intermediate.growAggregate(declaratorList, intermNode, initLocation);
+ }
+ else
+ {
+ return declaratorList;
+ }
+ }
+ else
+ {
+ recover();
+ return NULL;
+ }
+}
+
+void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
+{
+ if (typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
+ recover();
+ return;
+ }
+
+ const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
+ ASSERT(!layoutQualifier.isEmpty());
+
+ if (shaderVersion < 300)
+ {
+ error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
+ recover();
+ return;
+ }
+
+ if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
+ {
+ recover();
+ return;
+ }
+
+ if (layoutQualifier.matrixPacking != EmpUnspecified)
+ {
+ defaultMatrixPacking = layoutQualifier.matrixPacking;
+ }
+
+ if (layoutQualifier.blockStorage != EbsUnspecified)
+ {
+ defaultBlockStorage = layoutQualifier.blockStorage;
+ }
+}
+
+TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
+{
+ TOperator op = EOpNull;
+ if (publicType.userDef)
+ {
+ op = EOpConstructStruct;
+ }
+ else
+ {
+ switch (publicType.type)
+ {
+ case EbtFloat:
+ if (publicType.isMatrix())
+ {
+ // TODO: non-square matrices
+ switch(publicType.getCols())
+ {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ }
+ else
+ {
+ switch(publicType.getNominalSize())
+ {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+
+ case EbtInt:
+ switch(publicType.getNominalSize())
+ {
+ case 1: op = EOpConstructInt; break;
+ case 2: op = EOpConstructIVec2; break;
+ case 3: op = EOpConstructIVec3; break;
+ case 4: op = EOpConstructIVec4; break;
+ }
+ break;
+
+ case EbtUInt:
+ switch(publicType.getNominalSize())
+ {
+ case 1: op = EOpConstructUInt; break;
+ case 2: op = EOpConstructUVec2; break;
+ case 3: op = EOpConstructUVec3; break;
+ case 4: op = EOpConstructUVec4; break;
+ }
+ break;
+
+ case EbtBool:
+ switch(publicType.getNominalSize())
+ {
+ case 1: op = EOpConstructBool; break;
+ case 2: op = EOpConstructBVec2; break;
+ case 3: op = EOpConstructBVec3; break;
+ case 4: op = EOpConstructBVec4; break;
+ }
+ break;
+
+ default: break;
+ }
+
+ if (op == EOpNull)
+ {
+ error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
+ recover();
+ publicType.type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+
+ TString tempString;
+ TType type(publicType);
+ return new TFunction(&tempString, type, op);
+}
+
+// This function is used to test for the correctness of the parameters passed to various constructor functions
+// and also convert them to the right datatype if it is allowed and required.
+//
+// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
+//
+TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggrNode = node->getAsAggregate();
+
+ TFieldList::const_iterator memberTypes;
+ if (op == EOpConstructStruct)
+ memberTypes = type->getStruct()->fields().begin();
+
+ TType elementType = *type;
+ if (type->isArray())
+ elementType.clearArrayness();
+
+ bool singleArg;
+ if (aggrNode) {
+ if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
+ singleArg = true;
+ else
+ singleArg = false;
+ } else
+ singleArg = true;
+
+ TIntermTyped *newNode;
+ if (singleArg) {
+ // If structure constructor or array constructor is being called
+ // for only one parameter inside the structure, we need to call constructStruct function once.
+ if (type->isArray())
+ newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(node, (*memberTypes)->type(), 1, node->getLine(), false);
+ else
+ newNode = constructBuiltIn(type, op, node, node->getLine(), false);
+
+ if (newNode && newNode->getAsAggregate()) {
+ TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+ }
+
+ return newNode;
+ }
+
+ //
+ // Handle list of arguments.
+ //
+ TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
+ // if the structure constructor contains more than one parameter, then construct
+ // each parameter
+
+ int paramCount = 0; // keeps a track of the constructor parameter number being checked
+
+ // for each parameter to the constructor call, check to see if the right type is passed or convert them
+ // to the right type if possible (and allowed).
+ // for structure constructors, just check if the right type is passed, no conversion is allowed.
+
+ for (TIntermSequence::iterator p = sequenceVector.begin();
+ p != sequenceVector.end(); p++, paramCount++) {
+ if (type->isArray())
+ newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(*p, (memberTypes[paramCount])->type(), paramCount+1, node->getLine(), true);
+ else
+ newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
+
+ if (newNode) {
+ *p = newNode;
+ }
+ }
+
+ TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
+ TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+
+ return constructor;
+}
+
+TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
+{
+ bool canBeFolded = areAllChildConst(aggrNode);
+ aggrNode->setType(type);
+ if (canBeFolded) {
+ bool returnVal = false;
+ ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
+ if (aggrNode->getSequence().size() == 1) {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true);
+ }
+ else {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type);
+ }
+ if (returnVal)
+ return 0;
+
+ return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+ }
+
+ return 0;
+}
+
+// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
+// for the parameter to the constructor (passed to this function). Essentially, it converts
+// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
+// float, then float is converted to int.
+//
+// Returns 0 for an error or the constructed node.
+//
+TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset)
+{
+ TIntermTyped* newNode;
+ TOperator basicOp;
+
+ //
+ // First, convert types as needed.
+ //
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ basicOp = EOpConstructFloat;
+ break;
+
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ basicOp = EOpConstructInt;
+ break;
+
+ case EOpConstructUVec2:
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+ case EOpConstructUInt:
+ basicOp = EOpConstructUInt;
+ break;
+
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ basicOp = EOpConstructBool;
+ break;
+
+ default:
+ error(line, "unsupported construction", "");
+ recover();
+
+ return 0;
+ }
+ newNode = intermediate.addUnaryMath(basicOp, node, node->getLine());
+ if (newNode == 0) {
+ error(line, "can't convert", "constructor");
+ return 0;
+ }
+
+ //
+ // Now, if there still isn't an operation to do the construction, and we need one, add one.
+ //
+
+ // Otherwise, skip out early.
+ if (subset || (newNode != node && newNode->getType() == *type))
+ return newNode;
+
+ // setAggregateOperator will insert a new node for the constructor, as needed.
+ return intermediate.setAggregateOperator(newNode, op, line);
+}
+
+// This function tests for the type of the parameters to the structures constructors. Raises
+// an error message if the expected type does not match the parameter passed to the constructor.
+//
+// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
+//
+TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset)
+{
+ if (*type == node->getAsTyped()->getType()) {
+ if (subset)
+ return node->getAsTyped();
+ else
+ return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert parameter " << paramCount
+ << " from '" << node->getAsTyped()->getType().getBasicString()
+ << "' to '" << type->getBasicString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "constructor", extraInfo.c_str());
+ recover();
+ }
+
+ return 0;
+}
+
+//
+// This function returns the tree representation for the vector field(s) being accessed from contant vector.
+// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
+// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
+// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
+// a constant matrix.
+//
+TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ ConstantUnion *unionArray;
+ if (tempConstantNode) {
+ unionArray = tempConstantNode->getUnionArrayPointer();
+
+ if (!unionArray) {
+ return node;
+ }
+ } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
+ error(line, "Cannot offset into the vector", "Error");
+ recover();
+
+ return 0;
+ }
+
+ ConstantUnion* constArray = new ConstantUnion[fields.num];
+
+ for (int i = 0; i < fields.num; i++) {
+ if (fields.offsets[i] >= node->getType().getNominalSize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ fields.offsets[i] = 0;
+ }
+
+ constArray[i] = unionArray[fields.offsets[i]];
+
+ }
+ typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
+ return typedNode;
+}
+
+//
+// This function returns the column being accessed from a constant matrix. The values are retrieved from
+// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
+// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
+// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ if (index >= node->getType().getCols()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "matrix field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ int size = tempConstantNode->getType().getCols();
+ typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the matrix", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns an element of an array accessed from a constant array. The values are retrieved from
+// the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
+// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+ TType arrayElementType = node->getType();
+ arrayElementType.clearArrayness();
+
+ if (index >= node->getType().getArraySize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the array", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns the value of a particular field inside a constant structure from the symbol table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
+// function and returns the parse-tree with the values of the embedded/nested struct.
+//
+TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line)
+{
+ const TFieldList& fields = node->getType().getStruct()->fields();
+ size_t instanceSize = 0;
+
+ for (size_t index = 0; index < fields.size(); ++index) {
+ if (fields[index]->name() == identifier) {
+ break;
+ } else {
+ instanceSize += fields[index]->type()->getObjectSize();
+ }
+ }
+
+ TIntermTyped *typedNode;
+ TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
+ if (tempConstantNode) {
+ ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
+
+ typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
+ } else {
+ error(line, "Cannot offset into the structure", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+//
+// Interface/uniform blocks
+//
+TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
+ const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
+{
+ if (reservedErrorCheck(nameLine, blockName))
+ recover();
+
+ if (typeQualifier.qualifier != EvqUniform)
+ {
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
+ recover();
+ }
+
+ TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
+ if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
+ {
+ recover();
+ }
+
+ if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
+ }
+
+ if (blockLayoutQualifier.blockStorage == EbsUnspecified)
+ {
+ blockLayoutQualifier.blockStorage = defaultBlockStorage;
+ }
+
+ TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
+ if (!symbolTable.declare(*blockNameSymbol)) {
+ error(nameLine, "redefinition", blockName.c_str(), "interface block name");
+ recover();
+ }
+
+ // check for sampler types and apply layout qualifiers
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
+ TField* field = (*fieldList)[memberIndex];
+ TType* fieldType = field->type();
+ if (IsSampler(fieldType->getBasicType())) {
+ error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
+ recover();
+ }
+
+ const TQualifier qualifier = fieldType->getQualifier();
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ case EvqUniform:
+ break;
+ default:
+ error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
+ recover();
+ break;
+ }
+
+ // check layout qualifiers
+ TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
+ if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
+ {
+ recover();
+ }
+
+ if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
+ {
+ error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
+ recover();
+ }
+
+ if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
+ {
+ fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
+ }
+ else if (!fieldType->isMatrix())
+ {
+ error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
+ recover();
+ }
+
+ fieldType->setLayoutQualifier(fieldLayoutQualifier);
+ }
+
+ // add array index
+ int arraySize = 0;
+ if (arrayIndex != NULL)
+ {
+ if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
+ recover();
+ }
+
+ TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
+ TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
+
+ TString symbolName = "";
+ int symbolId = 0;
+
+ if (!instanceName)
+ {
+ // define symbols for the members of the interface block
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField* field = (*fieldList)[memberIndex];
+ TType* fieldType = field->type();
+
+ // set parent pointer of the field variable
+ fieldType->setInterfaceBlock(interfaceBlock);
+
+ TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
+ fieldVariable->setQualifier(typeQualifier.qualifier);
+
+ if (!symbolTable.declare(*fieldVariable)) {
+ error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
+ recover();
+ }
+ }
+ }
+ else
+ {
+ // add a symbol for this interface block
+ TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
+ instanceTypeDef->setQualifier(typeQualifier.qualifier);
+
+ if (!symbolTable.declare(*instanceTypeDef)) {
+ error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
+ recover();
+ }
+
+ symbolId = instanceTypeDef->getUniqueId();
+ symbolName = instanceTypeDef->getName();
+ }
+
+ TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
+ aggregate->setOp(EOpDeclaration);
+
+ exitStructDeclaration();
+ return aggregate;
+}
+
+bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
+{
+ ++structNestingLevel;
+
+ // Embedded structure definitions are not supported per GLSL ES spec.
+ // They aren't allowed in GLSL either, but we need to detect this here
+ // so we don't rely on the GLSL compiler to catch it.
+ if (structNestingLevel > 1) {
+ error(line, "", "Embedded struct definitions are not allowed");
+ return true;
+ }
+
+ return false;
+}
+
+void TParseContext::exitStructDeclaration()
+{
+ --structNestingLevel;
+}
+
+namespace {
+
+const int kWebGLMaxStructNesting = 4;
+
+} // namespace
+
+bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
+{
+ if (!IsWebGLBasedSpec(shaderSpec)) {
+ return false;
+ }
+
+ if (field.type()->getBasicType() != EbtStruct) {
+ return false;
+ }
+
+ // We're already inside a structure definition at this point, so add
+ // one to the field's struct nesting.
+ if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
+ std::stringstream reasonStream;
+ reasonStream << "Reference of struct type "
+ << field.type()->getStruct()->name().c_str()
+ << " exceeds maximum allowed nesting level of "
+ << kWebGLMaxStructNesting;
+ std::string reason = reasonStream.str();
+ error(line, reason.c_str(), field.name().c_str(), "");
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Parse an array index expression
+//
+TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
+{
+ TIntermTyped *indexedExpression = NULL;
+
+ if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
+ {
+ if (baseExpression->getAsSymbolNode())
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
+ }
+ else
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
+ }
+ recover();
+ }
+
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ int index = indexExpression->getAsConstantUnion()->getIConst(0);
+ if (index < 0)
+ {
+ std::stringstream infoStream;
+ infoStream << index;
+ std::string info = infoStream.str();
+ error(location, "negative index", info.c_str());
+ recover();
+ index = 0;
+ }
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ if (baseExpression->isArray())
+ {
+ // constant folding for arrays
+ indexedExpression = addConstArrayNode(index, baseExpression, location);
+ }
+ else if (baseExpression->isVector())
+ {
+ // constant folding for vectors
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
+ indexedExpression = addConstVectorNode(fields, baseExpression, location);
+ }
+ else if (baseExpression->isMatrix())
+ {
+ // constant folding for matrices
+ indexedExpression = addConstMatrixNode(index, baseExpression, location);
+ }
+ }
+ else
+ {
+ if (baseExpression->isArray())
+ {
+ if (index >= baseExpression->getType().getArraySize())
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array index out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(location, "", "[", extraInfo.c_str());
+ recover();
+ index = baseExpression->getType().getArraySize() - 1;
+ }
+ else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
+ {
+ error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
+ recover();
+ index = 0;
+ }
+ }
+ else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(location, "", "[", extraInfo.c_str());
+ recover();
+ index = baseExpression->getType().getNominalSize() - 1;
+ }
+
+ indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index);
+ indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
+ }
+ }
+ else
+ {
+ if (baseExpression->isInterfaceBlock())
+ {
+ error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions");
+ recover();
+ }
+ else if (baseExpression->getQualifier() == EvqFragmentOut)
+ {
+ error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions");
+ recover();
+ }
+
+ indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
+ }
+
+ if (indexedExpression == 0)
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
+ }
+ else if (baseExpression->isArray())
+ {
+ const TType &baseType = baseExpression->getType();
+ if (baseType.getStruct())
+ {
+ TType copyOfType(baseType.getStruct());
+ indexedExpression->setType(copyOfType);
+ }
+ else if (baseType.isInterfaceBlock())
+ {
+ TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0);
+ indexedExpression->setType(copyOfType);
+ }
+ else
+ {
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->getSecondarySize()));
+ }
+
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ }
+ }
+ else if (baseExpression->isMatrix())
+ {
+ TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getRows()));
+ }
+ else if (baseExpression->isVector())
+ {
+ TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
+ }
+ else
+ {
+ indexedExpression->setType(baseExpression->getType());
+ }
+
+ return indexedExpression;
+}
+
+TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation)
+{
+ TIntermTyped *indexedExpression = NULL;
+
+ if (baseExpression->isArray())
+ {
+ error(fieldLocation, "cannot apply dot operator to an array", ".");
+ recover();
+ }
+
+ if (baseExpression->isVector())
+ {
+ TVectorFields fields;
+ if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation))
+ {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ recover();
+ }
+
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ // constant folding for vector fields
+ indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
+ if (indexedExpression == 0)
+ {
+ recover();
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (int) (fieldString).size()));
+ }
+ }
+ else
+ {
+ TString vectorString = fieldString;
+ TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ }
+ else if (baseExpression->isMatrix())
+ {
+ TMatrixFields fields;
+ if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation))
+ {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol)
+ {
+ error(dotLocation, " non-scalar fields not implemented yet", ".");
+ recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary, baseExpression->getCols(), baseExpression->getRows()));
+ }
+ else
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
+ TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
+ }
+ }
+ else if (baseExpression->getBasicType() == EbtStruct)
+ {
+ bool fieldFound = false;
+ const TFieldList& fields = baseExpression->getType().getStruct()->fields();
+ if (fields.empty())
+ {
+ error(dotLocation, "structure has no fields", "Internal Error");
+ recover();
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i)
+ {
+ if (fields[i]->name() == fieldString)
+ {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound)
+ {
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
+ if (indexedExpression == 0)
+ {
+ recover();
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ indexedExpression->setType(*fields[i]->type());
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ }
+ }
+ else
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
+ indexedExpression->setType(*fields[i]->type());
+ }
+ }
+ else
+ {
+ error(dotLocation, " no such field in structure", fieldString.c_str());
+ recover();
+ indexedExpression = baseExpression;
+ }
+ }
+ }
+ else if (baseExpression->isInterfaceBlock())
+ {
+ bool fieldFound = false;
+ const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields();
+ if (fields.empty())
+ {
+ error(dotLocation, "interface block has no fields", "Internal Error");
+ recover();
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i)
+ {
+ if (fields[i]->name() == fieldString)
+ {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound)
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
+ indexedExpression->setType(*fields[i]->type());
+ }
+ else
+ {
+ error(dotLocation, " no such field in interface block", fieldString.c_str());
+ recover();
+ indexedExpression = baseExpression;
+ }
+ }
+ }
+ else
+ {
+ if (shaderVersion < 300)
+ {
+ error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
+ }
+ else
+ {
+ error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
+ }
+ recover();
+ indexedExpression = baseExpression;
+ }
+
+ return indexedExpression;
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine)
+{
+ TLayoutQualifier qualifier;
+
+ qualifier.location = -1;
+ qualifier.matrixPacking = EmpUnspecified;
+ qualifier.blockStorage = EbsUnspecified;
+
+ if (qualifierType == "shared")
+ {
+ qualifier.blockStorage = EbsShared;
+ }
+ else if (qualifierType == "packed")
+ {
+ qualifier.blockStorage = EbsPacked;
+ }
+ else if (qualifierType == "std140")
+ {
+ qualifier.blockStorage = EbsStd140;
+ }
+ else if (qualifierType == "row_major")
+ {
+ qualifier.matrixPacking = EmpRowMajor;
+ }
+ else if (qualifierType == "column_major")
+ {
+ qualifier.matrixPacking = EmpColumnMajor;
+ }
+ else if (qualifierType == "location")
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument");
+ recover();
+ }
+ else
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
+ recover();
+ }
+
+ return qualifier;
+}
+
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine)
+{
+ TLayoutQualifier qualifier;
+
+ qualifier.location = -1;
+ qualifier.matrixPacking = EmpUnspecified;
+ qualifier.blockStorage = EbsUnspecified;
+
+ if (qualifierType != "location")
+ {
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments");
+ recover();
+ }
+ else
+ {
+ // must check that location is non-negative
+ if (intValue < 0)
+ {
+ error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
+ recover();
+ }
+ else
+ {
+ qualifier.location = intValue;
+ }
+ }
+
+ return qualifier;
+}
+
+TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
+{
+ TLayoutQualifier joinedQualifier = leftQualifier;
+
+ if (rightQualifier.location != -1)
+ {
+ joinedQualifier.location = rightQualifier.location;
+ }
+ if (rightQualifier.matrixPacking != EmpUnspecified)
+ {
+ joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
+ }
+ if (rightQualifier.blockStorage != EbsUnspecified)
+ {
+ joinedQualifier.blockStorage = rightQualifier.blockStorage;
+ }
+
+ return joinedQualifier;
+}
+
+TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
+ const TSourceLoc &storageLoc, TQualifier storageQualifier)
+{
+ TQualifier mergedQualifier = EvqSmoothIn;
+
+ if (storageQualifier == EvqFragmentIn) {
+ if (interpolationQualifier == EvqSmooth)
+ mergedQualifier = EvqSmoothIn;
+ else if (interpolationQualifier == EvqFlat)
+ mergedQualifier = EvqFlatIn;
+ else UNREACHABLE();
+ }
+ else if (storageQualifier == EvqCentroidIn) {
+ if (interpolationQualifier == EvqSmooth)
+ mergedQualifier = EvqCentroidIn;
+ else if (interpolationQualifier == EvqFlat)
+ mergedQualifier = EvqFlatIn;
+ else UNREACHABLE();
+ }
+ else if (storageQualifier == EvqVertexOut) {
+ if (interpolationQualifier == EvqSmooth)
+ mergedQualifier = EvqSmoothOut;
+ else if (interpolationQualifier == EvqFlat)
+ mergedQualifier = EvqFlatOut;
+ else UNREACHABLE();
+ }
+ else if (storageQualifier == EvqCentroidOut) {
+ if (interpolationQualifier == EvqSmooth)
+ mergedQualifier = EvqCentroidOut;
+ else if (interpolationQualifier == EvqFlat)
+ mergedQualifier = EvqFlatOut;
+ else UNREACHABLE();
+ }
+ else {
+ error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier));
+ recover();
+
+ mergedQualifier = storageQualifier;
+ }
+
+ TPublicType type;
+ type.setBasic(EbtVoid, mergedQualifier, storageLoc);
+ return type;
+}
+
+TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList)
+{
+ if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier)) {
+ recover();
+ }
+
+ for (unsigned int i = 0; i < fieldList->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*fieldList)[i]->type();
+ type->setBasicType(typeSpecifier.type);
+ type->setPrimarySize(typeSpecifier.primarySize);
+ type->setSecondarySize(typeSpecifier.secondarySize);
+ type->setPrecision(typeSpecifier.precision);
+ type->setQualifier(typeSpecifier.qualifier);
+ type->setLayoutQualifier(typeSpecifier.layoutQualifier);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
+ recover();
+ }
+ if (typeSpecifier.array)
+ type->setArraySize(typeSpecifier.arraySize);
+ if (typeSpecifier.userDef) {
+ type->setStruct(typeSpecifier.userDef->getStruct());
+ }
+
+ if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) {
+ recover();
+ }
+ }
+
+ return fieldList;
+}
+
+TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList)
+{
+ TStructure* structure = new TStructure(structName, fieldList);
+ TType* structureType = new TType(structure);
+
+ structure->setUniqueId(TSymbolTable::nextUniqueId());
+
+ if (!structName->empty())
+ {
+ if (reservedErrorCheck(nameLine, *structName))
+ {
+ recover();
+ }
+ TVariable* userTypeDef = new TVariable(structName, *structureType, true);
+ if (!symbolTable.declare(*userTypeDef)) {
+ error(nameLine, "redefinition", structName->c_str(), "struct");
+ recover();
+ }
+ }
+
+ // ensure we do not specify any storage qualifiers on the struct members
+ for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
+ {
+ const TField &field = *(*fieldList)[typeListIndex];
+ const TQualifier qualifier = field.type()->getQualifier();
+ switch (qualifier)
+ {
+ case EvqGlobal:
+ case EvqTemporary:
+ break;
+ default:
+ error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
+ recover();
+ break;
+ }
+ }
+
+ TPublicType publicType;
+ publicType.setBasic(EbtStruct, EvqTemporary, structLine);
+ publicType.userDef = structureType;
+ exitStructDeclaration();
+
+ return publicType;
+}
+
+//
+// Parse an array of strings using yyparse.
+//
+// Returns 0 for success.
+//
+int PaParseStrings(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ if ((count == 0) || (string == NULL))
+ return 1;
+
+ if (glslang_initialize(context))
+ return 1;
+
+ int error = glslang_scan(count, string, length, context);
+ if (!error)
+ error = glslang_parse(context);
+
+ glslang_finalize(context);
+
+ return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
+}
+
+
+
diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.h b/chromium/third_party/angle/src/compiler/translator/ParseContext.h
new file mode 100644
index 00000000000..3cd4b915e3c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.h
@@ -0,0 +1,169 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef _PARSER_HELPER_INCLUDED_
+#define _PARSER_HELPER_INCLUDED_
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/DirectiveHandler.h"
+#include "compiler/translator/localintermediate.h"
+#include "compiler/translator/ShHandle.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/preprocessor/Preprocessor.h"
+
+struct TMatrixFields {
+ bool wholeRow;
+ bool wholeCol;
+ int row;
+ int col;
+};
+
+//
+// The following are extra variables needed during parsing, grouped together so
+// they can be passed to the parser without needing a global.
+//
+struct TParseContext {
+ TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
+ intermediate(interm),
+ symbolTable(symt),
+ shaderType(type),
+ shaderSpec(spec),
+ compileOptions(options),
+ sourcePath(sourcePath),
+ treeRoot(0),
+ loopNestingLevel(0),
+ structNestingLevel(0),
+ currentFunctionType(NULL),
+ functionReturnsValue(false),
+ checksPrecisionErrors(checksPrecErrors),
+ defaultMatrixPacking(EmpColumnMajor),
+ defaultBlockStorage(EbsShared),
+ diagnostics(is),
+ shaderVersion(100),
+ directiveHandler(ext, diagnostics, shaderVersion),
+ preprocessor(&diagnostics, &directiveHandler),
+ scanner(NULL) { }
+ TIntermediate& intermediate; // to hold and build a parse tree
+ TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
+ ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ int shaderVersion;
+ int compileOptions;
+ const char* sourcePath; // Path of source file or NULL.
+ TIntermNode* treeRoot; // root of parse tree being created
+ int loopNestingLevel; // 0 if outside all loops
+ int structNestingLevel; // incremented while parsing a struct declaration
+ const TType* currentFunctionType; // the return type of the function that's currently being parsed
+ bool functionReturnsValue; // true if a non-void function has a return
+ bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
+ bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
+ TLayoutMatrixPacking defaultMatrixPacking;
+ TLayoutBlockStorage defaultBlockStorage;
+ TString HashErrMsg;
+ TDiagnostics diagnostics;
+ TDirectiveHandler directiveHandler;
+ pp::Preprocessor preprocessor;
+ void* scanner;
+
+ int getShaderVersion() const { return shaderVersion; }
+ int numErrors() const { return diagnostics.numErrors(); }
+ TInfoSink& infoSink() { return diagnostics.infoSink(); }
+ void error(const TSourceLoc& loc, const char *reason, const char* token,
+ const char* extraInfo="");
+ void warning(const TSourceLoc& loc, const char* reason, const char* token,
+ const char* extraInfo="");
+ void trace(const char* str);
+ void recover();
+
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line);
+ bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, const TSourceLoc& line);
+
+ bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier);
+ void assignError(const TSourceLoc& line, const char* op, TString left, TString right);
+ void unaryOpError(const TSourceLoc& line, const char* op, TString operand);
+ void binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right);
+ bool precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type);
+ bool lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped*);
+ bool constErrorCheck(TIntermTyped* node);
+ bool integerErrorCheck(TIntermTyped* node, const char* token);
+ bool globalErrorCheck(const TSourceLoc& line, bool global, const char* token);
+ bool constructorErrorCheck(const TSourceLoc& line, TIntermNode*, TFunction&, TOperator, TType*);
+ bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size);
+ bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type);
+ bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type);
+ bool arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable);
+ bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&);
+ bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
+ bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
+ bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason);
+ bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType);
+ bool locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType);
+ bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type);
+ bool nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array);
+ bool nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable);
+ bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
+ bool extensionErrorCheck(const TSourceLoc& line, const TString&);
+ bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier);
+ bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
+
+ const TPragma& pragma() const { return directiveHandler.pragma(); }
+ const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
+ bool supportsExtension(const char* extension);
+ bool isExtensionEnabled(const char* extension) const;
+ void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior);
+ void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value);
+
+ bool containsSampler(TType& type);
+ bool areAllChildConst(TIntermAggregate* aggrNode);
+ const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int shaderVersion, bool *builtIn = 0);
+ bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
+
+ TPublicType addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier);
+ TPublicType addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier);
+ TIntermAggregate* parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier);
+ TIntermAggregate* parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression);
+ TIntermAggregate* parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer);
+ TIntermAggregate* parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier);
+ TIntermAggregate* parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression);
+ TIntermAggregate* parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer);
+ void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
+ TFunction *addConstructorFunc(TPublicType publicType);
+ TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
+ TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
+ TIntermTyped* constructStruct(TIntermNode*, TType*, int, const TSourceLoc&, bool subset);
+ TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, const TSourceLoc&, bool subset);
+ TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line);
+ TIntermTyped* addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
+ TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression);
+ TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation);
+
+ TFieldList *addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList);
+ TPublicType addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList);
+
+ TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
+ const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine);
+
+ TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine);
+ TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine);
+ TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier);
+ TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
+ const TSourceLoc &storageLoc, TQualifier storageQualifier);
+
+ // Performs an error check for embedded struct declarations.
+ // Returns true if an error was raised due to the declaration of
+ // this struct.
+ bool enterStructDeclaration(const TSourceLoc& line, const TString& identifier);
+ void exitStructDeclaration();
+
+ bool structNestingErrorCheck(const TSourceLoc& line, const TField& field);
+};
+
+int PaParseStrings(size_t count, const char* const string[], const int length[],
+ TParseContext* context);
+
+#endif // _PARSER_HELPER_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp
new file mode 100644
index 00000000000..abe70262f2d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp
@@ -0,0 +1,294 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/PoolAlloc.h"
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <stdio.h>
+
+#include "common/angleutils.h"
+#include "compiler/translator/InitializeGlobals.h"
+#include "compiler/translator/osinclude.h"
+
+OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializePoolIndex()
+{
+ assert(PoolIndex == OS_INVALID_TLS_INDEX);
+
+ PoolIndex = OS_AllocTLSIndex();
+ return PoolIndex != OS_INVALID_TLS_INDEX;
+}
+
+void FreePoolIndex()
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+
+ OS_FreeTLSIndex(PoolIndex);
+ PoolIndex = OS_INVALID_TLS_INDEX;
+}
+
+TPoolAllocator* GetGlobalPoolAllocator()
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+ return static_cast<TPoolAllocator*>(OS_GetTLSValue(PoolIndex));
+}
+
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+ OS_SetTLSValue(PoolIndex, poolAllocator);
+}
+
+//
+// Implement the functionality of the TPoolAllocator class, which
+// is documented in PoolAlloc.h.
+//
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
+ pageSize(growthIncrement),
+ alignment(allocationAlignment),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0)
+{
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4*1024)
+ pageSize = 4*1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
+ //
+ // Adjust alignment to be at least pointer aligned and
+ // power of 2.
+ //
+ size_t minAlign = sizeof(void*);
+ alignment &= ~(minAlign - 1);
+ if (alignment < minAlign)
+ alignment = minAlign;
+ size_t a = 1;
+ while (a < alignment)
+ a <<= 1;
+ alignment = a;
+ alignmentMask = a - 1;
+
+ //
+ // Align header skip
+ //
+ headerSkip = minAlign;
+ if (headerSkip < sizeof(tHeader)) {
+ headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+ }
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+ while (inUseList) {
+ tHeader* next = inUseList->nextPage;
+ inUseList->~tHeader();
+ delete [] reinterpret_cast<char*>(inUseList);
+ inUseList = next;
+ }
+
+ // We should not check the guard blocks
+ // here, because we did it already when the block was
+ // placed into the free list.
+ //
+ while (freeList) {
+ tHeader* next = freeList->nextPage;
+ delete [] reinterpret_cast<char*>(freeList);
+ freeList = next;
+ }
+}
+
+// Support MSVC++ 6.0
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal = 0xfe;
+const unsigned char TAllocation::userDataFill = 0xcd;
+
+#ifdef GUARD_BLOCKS
+ const size_t TAllocation::guardBlockSize = 16;
+#else
+ const size_t TAllocation::guardBlockSize = 0;
+#endif
+
+//
+// Check a single guard block for damage
+//
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+{
+#ifdef GUARD_BLOCKS
+ for (size_t x = 0; x < guardBlockSize; x++) {
+ if (blockMem[x] != val) {
+ char assertMsg[80];
+
+ // We don't print the assert message. It's here just to be helpful.
+#if defined(_MSC_VER)
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n",
+ locText, size, data());
+#else
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
+ locText, size, data());
+#endif
+ assert(0 && "PoolAlloc: Damage in guard block");
+ }
+ }
+#endif
+}
+
+
+void TPoolAllocator::push()
+{
+ tAllocState state = { currentPageOffset, inUseList };
+
+ stack.push_back(state);
+
+ //
+ // Indicate there is no current page to allocate from.
+ //
+ currentPageOffset = pageSize;
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+ if (stack.size() < 1)
+ return;
+
+ tHeader* page = stack.back().page;
+ currentPageOffset = stack.back().offset;
+
+ while (inUseList != page) {
+ // invoke destructor to free allocation list
+ inUseList->~tHeader();
+
+ tHeader* nextInUse = inUseList->nextPage;
+ if (inUseList->pageCount > 1)
+ delete [] reinterpret_cast<char*>(inUseList);
+ else {
+ inUseList->nextPage = freeList;
+ freeList = inUseList;
+ }
+ inUseList = nextInUse;
+ }
+
+ stack.pop_back();
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+ while (stack.size() > 0)
+ pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+ //
+ // Just keep some interesting statistics.
+ //
+ ++numCalls;
+ totalBytes += numBytes;
+
+ // If we are using guard blocks, all allocations are bracketed by
+ // them: [guardblock][allocation][guardblock]. numBytes is how
+ // much memory the caller asked for. allocationSize is the total
+ // size including guard blocks. In release build,
+ // guardBlockSize=0 and this all gets optimized away.
+ size_t allocationSize = TAllocation::allocationSize(numBytes);
+ // Detect integer overflow.
+ if (allocationSize < numBytes)
+ return 0;
+
+ //
+ // Do the allocation, most likely case first, for efficiency.
+ // This step could be moved to be inline sometime.
+ //
+ if (allocationSize <= pageSize - currentPageOffset) {
+ //
+ // Safe to allocate from currentPageOffset.
+ //
+ unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
+ currentPageOffset += allocationSize;
+ currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, memory, numBytes);
+ }
+
+ if (allocationSize > pageSize - headerSkip) {
+ //
+ // Do a multi-page allocation. Don't mix these with the others.
+ // The OS is efficient and allocating and free-ing multiple pages.
+ //
+ size_t numBytesToAlloc = allocationSize + headerSkip;
+ // Detect integer overflow.
+ if (numBytesToAlloc < allocationSize)
+ return 0;
+
+ tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+ if (memory == 0)
+ return 0;
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+ inUseList = memory;
+
+ currentPageOffset = pageSize; // make next allocation come from a new page
+
+ // No guard blocks for multi-page allocations (yet)
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
+ }
+
+ //
+ // Need a simple page to allocate from.
+ //
+ tHeader* memory;
+ if (freeList) {
+ memory = freeList;
+ freeList = freeList->nextPage;
+ } else {
+ memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+ if (memory == 0)
+ return 0;
+ }
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, 1);
+ inUseList = memory;
+
+ unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
+ currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, ret, numBytes);
+}
+
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+ for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+ alloc->check();
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h
new file mode 100644
index 00000000000..edd249c4d3a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h
@@ -0,0 +1,300 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#define GUARD_BLOCKS // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+// typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <stddef.h>
+#include <string.h>
+#include <vector>
+
+// If we are using guard blocks, we must track each indivual
+// allocation. If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+ TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+ size(size), mem(mem), prevAlloc(prev) {
+ // Allocations are bracketed:
+ // [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+ // This would be cleaner with if (guardBlockSize)..., but that
+ // makes the compiler print warnings about 0 length memsets,
+ // even with the if() protecting them.
+#ifdef GUARD_BLOCKS
+ memset(preGuard(), guardBlockBeginVal, guardBlockSize);
+ memset(data(), userDataFill, size);
+ memset(postGuard(), guardBlockEndVal, guardBlockSize);
+#endif
+ }
+
+ void check() const {
+ checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
+ checkGuardBlock(postGuard(), guardBlockEndVal, "after");
+ }
+
+ void checkAllocList() const;
+
+ // Return total size needed to accomodate user buffer of 'size',
+ // plus our tracking data.
+ inline static size_t allocationSize(size_t size) {
+ return size + 2 * guardBlockSize + headerSize();
+ }
+
+ // Offset from surrounding buffer to get to user data buffer.
+ inline static unsigned char* offsetAllocation(unsigned char* m) {
+ return m + guardBlockSize + headerSize();
+ }
+
+private:
+ void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+ // Find offsets to pre and post guard blocks, and user data buffer
+ unsigned char* preGuard() const { return mem + headerSize(); }
+ unsigned char* data() const { return preGuard() + guardBlockSize; }
+ unsigned char* postGuard() const { return data() + size; }
+
+ size_t size; // size of the user data area
+ unsigned char* mem; // beginning of our allocation (pts to header)
+ TAllocation* prevAlloc; // prior allocation in the chain
+
+ // Support MSVC++ 6.0
+ const static unsigned char guardBlockBeginVal;
+ const static unsigned char guardBlockEndVal;
+ const static unsigned char userDataFill;
+
+ const static size_t guardBlockSize;
+#ifdef GUARD_BLOCKS
+ inline static size_t headerSize() { return sizeof(TAllocation); }
+#else
+ inline static size_t headerSize() { return 0; }
+#endif
+};
+
+//
+// There are several stacks. One is to track the pushing and popping
+// of the user, and not yet implemented. The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS. Multi-page allocations
+// are returned to the OS. Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size. But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+ TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+ //
+ // Don't call the destructor just to free up the memory, call pop()
+ //
+ ~TPoolAllocator();
+
+ //
+ // Call push() to establish a new place to pop memory too. Does not
+ // have to be called to get things started.
+ //
+ void push();
+
+ //
+ // Call pop() to free all memory allocated since the last call to push(),
+ // or if no last call to push, frees all memory since first allocation.
+ //
+ void pop();
+
+ //
+ // Call popAll() to free all memory allocated.
+ //
+ void popAll();
+
+ //
+ // Call allocate() to actually acquire memory. Returns 0 if no memory
+ // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+ //
+ void* allocate(size_t numBytes);
+
+ //
+ // There is no deallocate. The point of this class is that
+ // deallocation can be skipped by the user of it, as the model
+ // of use is to simultaneously deallocate everything at once
+ // by calling pop(), and to not have to solve memory leak problems.
+ //
+
+protected:
+ friend struct tHeader;
+
+ struct tHeader {
+ tHeader(tHeader* nextPage, size_t pageCount) :
+ nextPage(nextPage),
+ pageCount(pageCount)
+#ifdef GUARD_BLOCKS
+ , lastAllocation(0)
+#endif
+ { }
+
+ ~tHeader() {
+#ifdef GUARD_BLOCKS
+ if (lastAllocation)
+ lastAllocation->checkAllocList();
+#endif
+ }
+
+ tHeader* nextPage;
+ size_t pageCount;
+#ifdef GUARD_BLOCKS
+ TAllocation* lastAllocation;
+#endif
+ };
+
+ struct tAllocState {
+ size_t offset;
+ tHeader* page;
+ };
+ typedef std::vector<tAllocState> tAllocStack;
+
+ // Track allocations if and only if we're using guard blocks
+ void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+#ifdef GUARD_BLOCKS
+ new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+ block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+ // This is optimized entirely away if GUARD_BLOCKS is not defined.
+ return TAllocation::offsetAllocation(memory);
+ }
+
+ size_t pageSize; // granularity of allocation from the OS
+ size_t alignment; // all returned allocations will be aligned at
+ // this granularity, which will be a power of 2
+ size_t alignmentMask;
+ size_t headerSkip; // amount of memory to skip to make room for the
+ // header (basically, size of header, rounded
+ // up to make it aligned
+ size_t currentPageOffset; // next offset in top of inUseList to allocate from
+ tHeader* freeList; // list of popped memory
+ tHeader* inUseList; // list of all memory currently being used
+ tAllocStack stack; // stack of where to allocate from, to partition pool
+
+ int numCalls; // just an interesting statistic
+ size_t totalBytes; // just an interesting statistic
+private:
+ TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator
+ TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor
+};
+
+
+//
+// There could potentially be many pools with pops happening at
+// different times. But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+extern TPoolAllocator* GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator);
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class Other>
+ struct rebind {
+ typedef pool_allocator<Other> other;
+ };
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pool_allocator() : allocator(GetGlobalPoolAllocator()) { }
+ pool_allocator(TPoolAllocator& a) : allocator(&a) { }
+ pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+ template <class Other>
+ pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
+ allocator = p.allocator;
+ return *this;
+ }
+
+ template<class Other>
+ pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
+
+#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
+ // libCStd on some platforms have a different allocate/deallocate interface.
+ // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
+ // allocated, not the number of elements.
+ void* allocate(size_type n) {
+ return getAllocator().allocate(n);
+ }
+ void* allocate(size_type n, const void*) {
+ return getAllocator().allocate(n);
+ }
+ void deallocate(void*, size_type) {}
+#else
+ pointer allocate(size_type n) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ pointer allocate(size_type n, const void*) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ void deallocate(pointer, size_type) {}
+#endif // _RWSTD_ALLOCATOR
+
+ void construct(pointer p, const T& val) { new ((void *)p) T(val); }
+ void destroy(pointer p) { p->T::~T(); }
+
+ bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
+ bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+
+ size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+ size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+ void setAllocator(TPoolAllocator* a) { allocator = a; }
+ TPoolAllocator& getAllocator() const { return *allocator; }
+
+protected:
+ TPoolAllocator* allocator;
+};
+
+#endif // _POOLALLOC_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/Pragma.h b/chromium/third_party/angle/src/compiler/translator/Pragma.h
new file mode 100644
index 00000000000..2f744123b82
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Pragma.h
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PRAGMA_H_
+#define COMPILER_PRAGMA_H_
+
+struct TPragma {
+ // By default optimization is turned on and debug is turned off.
+ TPragma() : optimize(true), debug(false) { }
+ TPragma(bool o, bool d) : optimize(o), debug(d) { }
+
+ bool optimize;
+ bool debug;
+};
+
+#endif // COMPILER_PRAGMA_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp
new file mode 100644
index 00000000000..1ba087e1765
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/intermediate.h"
+
+class TAliveTraverser : public TIntermTraverser {
+public:
+ TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q)
+ {
+ }
+
+ bool wasFound() { return found; }
+
+protected:
+ bool found;
+ TQualifier qualifier;
+
+ void visitSymbol(TIntermSymbol*);
+ bool visitSelection(Visit, TIntermSelection*);
+};
+
+//
+// Report whether or not a variable of the given qualifier type
+// is guaranteed written. Not always possible to determine if
+// it is written conditionally.
+//
+// ?? It does not do this well yet, this is just a place holder
+// that simply determines if it was reference at all, anywhere.
+//
+bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
+{
+ TAliveTraverser it(qualifier);
+
+ if (node)
+ node->traverse(&it);
+
+ return it.wasFound();
+}
+
+void TAliveTraverser::visitSymbol(TIntermSymbol* node)
+{
+ //
+ // If it's what we're looking for, record it.
+ //
+ if (node->getQualifier() == qualifier)
+ found = true;
+}
+
+bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node)
+{
+ if (wasFound())
+ return false;
+
+ return true;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h
new file mode 100644
index 00000000000..872a06f7219
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp b/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp
new file mode 100644
index 00000000000..e381c326900
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/RemoveTree.h"
+
+//
+// Code to delete the intermediate tree.
+//
+void RemoveAllTreeNodes(TIntermNode* root)
+{
+ std::queue<TIntermNode*> nodeQueue;
+
+ nodeQueue.push(root);
+
+ while (!nodeQueue.empty())
+ {
+ TIntermNode *node = nodeQueue.front();
+ nodeQueue.pop();
+
+ node->enqueueChildren(&nodeQueue);
+
+ delete node;
+ }
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveTree.h b/chromium/third_party/angle/src/compiler/translator/RemoveTree.h
new file mode 100644
index 00000000000..97a821679c2
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/RemoveTree.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+void RemoveAllTreeNodes(TIntermNode*);
diff --git a/chromium/third_party/angle/src/compiler/translator/RenameFunction.h b/chromium/third_party/angle/src/compiler/translator/RenameFunction.h
new file mode 100644
index 00000000000..1f7fb16c459
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/RenameFunction.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_RENAME_FUNCTION
+#define COMPILER_RENAME_FUNCTION
+
+#include "compiler/translator/intermediate.h"
+
+//
+// Renames a function, including its declaration and any calls to it.
+//
+class RenameFunction : public TIntermTraverser
+{
+public:
+ RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
+ : TIntermTraverser(true, false, false)
+ , mOldFunctionName(oldFunctionName)
+ , mNewFunctionName(newFunctionName) {}
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ TOperator op = node->getOp();
+ if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
+ node->setName(mNewFunctionName);
+ return true;
+ }
+
+private:
+ const TString mOldFunctionName;
+ const TString mNewFunctionName;
+};
+
+#endif // COMPILER_RENAME_FUNCTION
diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp
new file mode 100644
index 00000000000..46e510c31b9
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp
@@ -0,0 +1,132 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteElseBlocks.cpp: Implementation for tree transform to change
+// all if-else blocks to if-if blocks.
+//
+
+#include "compiler/translator/RewriteElseBlocks.h"
+#include "compiler/translator/NodeSearch.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
+{
+ TType variableType(type, EbpHigh, EvqInternal);
+ return new TIntermSymbol(-1, name, variableType);
+}
+
+TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
+{
+ TIntermBinary *binary = new TIntermBinary(op);
+ binary->setLeft(left);
+ binary->setRight(right);
+ binary->setType(resultType);
+ return binary;
+}
+
+TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
+{
+ TIntermUnary *unary = new TIntermUnary(op, operand->getType());
+ unary->setOperand(operand);
+ return unary;
+}
+
+ElseBlockRewriter::ElseBlockRewriter()
+ : TIntermTraverser(true, false, true, false),
+ mTemporaryIndex(0),
+ mFunctionType(NULL)
+{}
+
+bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ if (visit == PostVisit)
+ {
+ for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++)
+ {
+ TIntermNode *statement = node->getSequence()[statementIndex];
+ TIntermSelection *selection = statement->getAsSelectionNode();
+ if (selection && selection->getFalseBlock() != NULL)
+ {
+ // Check for if / else if
+ TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
+ if (elseIfBranch)
+ {
+ selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch));
+ delete elseIfBranch;
+ }
+
+ node->getSequence()[statementIndex] = rewriteSelection(selection);
+ delete selection;
+ }
+ }
+ }
+ break;
+
+ case EOpFunction:
+ // Store the current function context (see comment below)
+ mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
+ break;
+
+ default: break;
+ }
+
+ return true;
+}
+
+TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
+{
+ ASSERT(selection->getFalseBlock() != NULL);
+
+ TString temporaryName = "cond_" + str(mTemporaryIndex++);
+ TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
+ TType resultType(EbtBool, EbpUndefined);
+ TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool);
+ TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool);
+ TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
+ TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
+ typedCondition, resultType);
+ TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
+ TIntermNode *negatedElse = NULL;
+
+ // crbug.com/346463
+ // D3D generates error messages claiming a function has no return value, when rewriting
+ // an if-else clause that returns something non-void in a function. By appending dummy
+ // returns (that are unreachable) we can silence this compile error.
+ if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
+ {
+ TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
+ mFunctionType->getBasicString();
+ TString rawText = "return (" + typeString + ")0";
+ negatedElse = new TIntermRaw(*mFunctionType, rawText);
+ }
+
+ TIntermSelection *falseBlock = new TIntermSelection(negatedCondition,
+ selection->getFalseBlock(), negatedElse);
+ TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC,
+ selection->getTrueBlock(), falseBlock);
+
+ TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
+ declaration->getSequence().push_back(storeCondition);
+
+ TIntermAggregate *block = new TIntermAggregate(EOpSequence);
+ block->getSequence().push_back(declaration);
+ block->getSequence().push_back(newIfElse);
+
+ return block;
+}
+
+void RewriteElseBlocks(TIntermNode *node)
+{
+ ElseBlockRewriter rewriter;
+ node->traverse(&rewriter);
+}
+
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h
new file mode 100644
index 00000000000..172928f7254
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// RewriteElseBlocks.h: Prototype for tree transform to change
+// all if-else blocks to if-if blocks.
+//
+
+#ifndef COMPILER_REWRITE_ELSE_BLOCKS_H_
+#define COMPILER_REWRITE_ELSE_BLOCKS_H_
+
+#include "compiler/translator/intermediate.h"
+
+namespace sh
+{
+
+class ElseBlockRewriter : public TIntermTraverser
+{
+ public:
+ ElseBlockRewriter();
+
+ protected:
+ bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
+
+ private:
+ int mTemporaryIndex;
+ const TType *mFunctionType;
+
+ TIntermNode *rewriteSelection(TIntermSelection *selection);
+};
+
+void RewriteElseBlocks(TIntermNode *node);
+
+}
+
+#endif // COMPILER_REWRITE_ELSE_BLOCKS_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp
new file mode 100644
index 00000000000..f78c84e370d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#include "compiler/translator/SearchSymbol.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/OutputHLSL.h"
+
+namespace sh
+{
+SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+{
+ match = false;
+}
+
+void SearchSymbol::traverse(TIntermNode *node)
+{
+ node->traverse(this);
+}
+
+void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode)
+{
+ if (symbolNode->getSymbol() == mSymbol)
+ {
+ match = true;
+ }
+}
+
+bool SearchSymbol::foundMatch() const
+{
+ return match;
+}
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h
new file mode 100644
index 00000000000..8ddd3cb1ac3
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#ifndef COMPILER_SEARCHSYMBOL_H_
+#define COMPILER_SEARCHSYMBOL_H_
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/ParseContext.h"
+
+namespace sh
+{
+class SearchSymbol : public TIntermTraverser
+{
+ public:
+ SearchSymbol(const TString &symbol);
+
+ void traverse(TIntermNode *node);
+ void visitSymbol(TIntermSymbol *symbolNode);
+
+ bool foundMatch() const;
+
+ protected:
+ const TString &mSymbol;
+ bool match;
+};
+}
+
+#endif // COMPILER_SEARCHSYMBOL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/ShHandle.h b/chromium/third_party/angle/src/compiler/translator/ShHandle.h
new file mode 100644
index 00000000000..bb6a60c519f
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ShHandle.h
@@ -0,0 +1,180 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SHHANDLE_INCLUDED_
+#define _SHHANDLE_INCLUDED_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/VariableInfo.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+class TCompiler;
+class TDependencyGraph;
+class TranslatorHLSL;
+
+//
+// Helper function to identify specs that are based on the WebGL spec,
+// like the CSS Shaders spec.
+//
+bool IsWebGLBasedSpec(ShShaderSpec spec);
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+ TShHandleBase();
+ virtual ~TShHandleBase();
+ virtual TCompiler* getAsCompiler() { return 0; }
+ virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; }
+
+protected:
+ // Memory allocator. Allocates and tracks memory required by the compiler.
+ // Deallocates all memory when compiler is destructed.
+ TPoolAllocator allocator;
+};
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+ TCompiler(ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+ virtual ~TCompiler();
+ virtual TCompiler* getAsCompiler() { return this; }
+
+ bool Init(const ShBuiltInResources& resources);
+ bool compile(const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions);
+
+ // Get results of the last compilation.
+ int getShaderVersion() const { return shaderVersion; }
+ TInfoSink& getInfoSink() { return infoSink; }
+ const TVariableInfoList& getAttribs() const { return attribs; }
+ const TVariableInfoList& getUniforms() const { return uniforms; }
+ const TVariableInfoList& getVaryings() const { return varyings; }
+
+ ShHashFunction64 getHashFunction() const { return hashFunction; }
+ NameMap& getNameMap() { return nameMap; }
+ TSymbolTable& getSymbolTable() { return symbolTable; }
+ ShShaderSpec getShaderSpec() const { return shaderSpec; }
+ ShShaderOutput getOutputType() const { return outputType; }
+ std::string getBuiltInResourcesString() const { return builtInResourcesString; }
+
+protected:
+ ShShaderType getShaderType() const { return shaderType; }
+ // Initialize symbol-table with built-in symbols.
+ bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
+ // Compute the string representation of the built-in resources
+ void setResourceString();
+ // Clears the results from the previous compilation.
+ void clearResults();
+ // Return true if function recursion is detected or call depth exceeded.
+ bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth);
+ // Returns true if a program has no conflicting or missing fragment outputs
+ bool validateOutputs(TIntermNode* root);
+ // Rewrites a shader's intermediate tree according to the CSS Shaders spec.
+ void rewriteCSSShader(TIntermNode* root);
+ // Returns true if the given shader does not exceed the minimum
+ // functionality mandated in GLSL 1.0 spec Appendix A.
+ bool validateLimitations(TIntermNode* root);
+ // Collect info for all attribs, uniforms, varyings.
+ void collectVariables(TIntermNode* root);
+ // Translate to object code.
+ virtual void translate(TIntermNode* root) = 0;
+ // Returns true if, after applying the packing rules in the GLSL 1.017 spec
+ // Appendix A, section 7, the shader does not use too many uniforms.
+ bool enforcePackingRestrictions();
+ // Insert statements to initialize varyings without static use in the beginning
+ // of main(). It is to work around a Mac driver where such varyings in a vertex
+ // shader may be optimized out incorrectly at compile time, causing a link failure.
+ // This function should only be applied to vertex shaders.
+ void initializeVaryingsWithoutStaticUse(TIntermNode* root);
+ // Insert gl_Position = vec4(0,0,0,0) to the beginning of main().
+ // It is to work around a Linux driver bug where missing this causes compile failure
+ // while spec says it is allowed.
+ // This function should only be applied to vertex shaders.
+ void initializeGLPosition(TIntermNode* root);
+ // Returns true if the shader passes the restrictions that aim to prevent timing attacks.
+ bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
+ // Returns true if the shader does not use samplers.
+ bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
+ // Returns true if the shader does not use sampler dependent values to affect control
+ // flow or in operations whose time can depend on the input values.
+ bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
+ // Return true if the maximum expression complexity is below the limit.
+ bool limitExpressionComplexity(TIntermNode* root);
+ // Get built-in extensions with default behavior.
+ const TExtensionBehavior& getExtensionBehavior() const;
+ // Get the resources set by InitBuiltInSymbolTable
+ const ShBuiltInResources& getResources() const;
+
+ const ArrayBoundsClamper& getArrayBoundsClamper() const;
+ ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
+ const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+
+private:
+ ShShaderType shaderType;
+ ShShaderSpec shaderSpec;
+ ShShaderOutput outputType;
+
+ int maxUniformVectors;
+ int maxExpressionComplexity;
+ int maxCallStackDepth;
+
+ ShBuiltInResources compileResources;
+ std::string builtInResourcesString;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable symbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior extensionBehavior;
+ bool fragmentPrecisionHigh;
+
+ ArrayBoundsClamper arrayBoundsClamper;
+ ShArrayIndexClampingStrategy clampingStrategy;
+ BuiltInFunctionEmulator builtInFunctionEmulator;
+
+ // Results of compilation.
+ int shaderVersion;
+ TInfoSink infoSink; // Output sink.
+ TVariableInfoList attribs; // Active attributes in the compiled shader.
+ TVariableInfoList uniforms; // Active uniforms in the compiled shader.
+ TVariableInfoList varyings; // Varyings in the compiled shader.
+
+ // name hashing.
+ ShHashFunction64 hashFunction;
+ NameMap nameMap;
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+void DeleteCompiler(TCompiler*);
+
+#endif // _SHHANDLE_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp
new file mode 100644
index 00000000000..bf0587a34ce
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp
@@ -0,0 +1,445 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Implement the top-level of interface to the compiler,
+// as defined in ShaderLang.h
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/translator/InitializeDll.h"
+#include "compiler/translator/length_limits.h"
+#include "compiler/translator/ShHandle.h"
+#include "compiler/translator/TranslatorHLSL.h"
+#include "compiler/translator/VariablePacker.h"
+
+static bool isInitialized = false;
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+static bool checkVariableMaxLengths(const ShHandle handle,
+ size_t expectedValue)
+{
+ size_t activeUniformLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
+ size_t activeAttribLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
+ size_t varyingLimit = 0;
+ ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit);
+ return (expectedValue == activeUniformLimit &&
+ expectedValue == activeAttribLimit &&
+ expectedValue == varyingLimit);
+}
+
+static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
+{
+ size_t mappedNameMaxLength = 0;
+ ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
+ return (expectedValue == mappedNameMaxLength);
+}
+
+//
+// Driver must call this first, once, before doing any other compiler operations.
+// Subsequent calls to this function are no-op.
+//
+int ShInitialize()
+{
+ if (!isInitialized)
+ {
+ isInitialized = InitProcess();
+ }
+ return isInitialized ? 1 : 0;
+}
+
+//
+// Cleanup symbol tables
+//
+int ShFinalize()
+{
+ if (isInitialized)
+ {
+ DetachProcess();
+ isInitialized = false;
+ }
+ return 1;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(ShBuiltInResources* resources)
+{
+ // Constants.
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ // Extensions.
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+ resources->ARB_texture_rectangle = 0;
+ resources->EXT_draw_buffers = 0;
+ resources->EXT_frag_depth = 0;
+ resources->EXT_shader_texture_lod = 0;
+
+ // Disable highp precision in fragment shader by default.
+ resources->FragmentPrecisionHigh = 0;
+
+ // GLSL ES 3.0 constants.
+ resources->MaxVertexOutputVectors = 16;
+ resources->MaxFragmentInputVectors = 15;
+ resources->MinProgramTexelOffset = -8;
+ resources->MaxProgramTexelOffset = 7;
+
+ // Disable name hashing by default.
+ resources->HashFunction = NULL;
+
+ resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
+
+ resources->MaxExpressionComplexity = 256;
+ resources->MaxCallStackDepth = 256;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources)
+{
+ TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ // Generate built-in symbol table.
+ if (!compiler->Init(*resources)) {
+ ShDestruct(base);
+ return 0;
+ }
+
+ return reinterpret_cast<void*>(base);
+}
+
+void ShDestruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString)
+{
+ if (!handle || !outString)
+ {
+ return;
+ }
+
+ TShHandleBase *base = static_cast<TShHandleBase*>(handle);
+ TCompiler *compiler = base->getAsCompiler();
+ if (!compiler)
+ {
+ return;
+ }
+
+ strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen);
+ outString[outStringLen - 1] = '\0';
+}
+//
+// Do an actual compile on the given strings. The result is left
+// in the given compile object.
+//
+// Return: The return value of ShCompile is really boolean, indicating
+// success or failure.
+//
+int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions)
+{
+ if (handle == 0)
+ return 0;
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
+ return success ? 1 : 0;
+}
+
+void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ switch(pname)
+ {
+ case SH_INFO_LOG_LENGTH:
+ *params = compiler->getInfoSink().info.size() + 1;
+ break;
+ case SH_OBJECT_CODE_LENGTH:
+ *params = compiler->getInfoSink().obj.size() + 1;
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ *params = compiler->getUniforms().size();
+ break;
+ case SH_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ break;
+ case SH_ACTIVE_ATTRIBUTES:
+ *params = compiler->getAttribs().size();
+ break;
+ case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ break;
+ case SH_VARYINGS:
+ *params = compiler->getVaryings().size();
+ break;
+ case SH_VARYING_MAX_LENGTH:
+ *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ break;
+ case SH_MAPPED_NAME_MAX_LENGTH:
+ // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
+ // handle array and struct dereferences.
+ *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ break;
+ case SH_NAME_MAX_LENGTH:
+ *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ break;
+ case SH_HASHED_NAME_MAX_LENGTH:
+ if (compiler->getHashFunction() == NULL) {
+ *params = 0;
+ } else {
+ // 64 bits hashing output requires 16 bytes for hex
+ // representation.
+ const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
+ (void)HashedNamePrefix;
+ *params = 16 + sizeof(HashedNamePrefix);
+ }
+ break;
+ case SH_HASHED_NAMES_COUNT:
+ *params = compiler->getNameMap().size();
+ break;
+ case SH_SHADER_VERSION:
+ *params = compiler->getShaderVersion();
+ break;
+ case SH_RESOURCES_STRING_LENGTH:
+ *params = compiler->getBuiltInResourcesString().length() + 1;
+ break;
+ case SH_OUTPUT_TYPE:
+ *params = compiler->getOutputType();
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+void ShGetInfoLog(const ShHandle handle, char* infoLog)
+{
+ if (!handle || !infoLog)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(infoLog, infoSink.info.c_str());
+}
+
+//
+// Return any object code.
+//
+void ShGetObjectCode(const ShHandle handle, char* objCode)
+{
+ if (!handle || !objCode)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(objCode, infoSink.obj.c_str());
+}
+
+void ShGetVariableInfo(const ShHandle handle,
+ ShShaderInfo varType,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ ShPrecisionType* precision,
+ int* staticUse,
+ char* name,
+ char* mappedName)
+{
+ if (!handle || !size || !type || !precision || !staticUse || !name)
+ return;
+ ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
+ (varType == SH_ACTIVE_UNIFORMS) ||
+ (varType == SH_VARYINGS));
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return;
+
+ const TVariableInfoList& varList =
+ varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() :
+ (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() :
+ compiler->getVaryings());
+ if (index < 0 || index >= static_cast<int>(varList.size()))
+ return;
+
+ const TVariableInfo& varInfo = varList[index];
+ if (length) *length = varInfo.name.size();
+ *size = varInfo.size;
+ *type = varInfo.type;
+ switch (varInfo.precision) {
+ case EbpLow:
+ *precision = SH_PRECISION_LOWP;
+ break;
+ case EbpMedium:
+ *precision = SH_PRECISION_MEDIUMP;
+ break;
+ case EbpHigh:
+ *precision = SH_PRECISION_HIGHP;
+ break;
+ default:
+ // Some types does not support precision, for example, boolean.
+ *precision = SH_PRECISION_UNDEFINED;
+ break;
+ }
+ *staticUse = varInfo.staticUse ? 1 : 0;
+
+ // This size must match that queried by
+ // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH
+ // in ShGetInfo, below.
+ size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ ASSERT(checkVariableMaxLengths(handle, variableLength));
+ strncpy(name, varInfo.name.c_str(), variableLength);
+ name[variableLength - 1] = 0;
+ if (mappedName) {
+ // This size must match that queried by
+ // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
+ size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec());
+ ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
+ strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
+ mappedName[maxMappedNameLength - 1] = 0;
+ }
+}
+
+void ShGetNameHashingEntry(const ShHandle handle,
+ int index,
+ char* name,
+ char* hashedName)
+{
+ if (!handle || !name || !hashedName || index < 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ const NameMap& nameMap = compiler->getNameMap();
+ if (index >= static_cast<int>(nameMap.size()))
+ return;
+
+ NameMap::const_iterator it = nameMap.begin();
+ for (int i = 0; i < index; ++i)
+ ++it;
+
+ size_t len = it->first.length() + 1;
+ size_t max_len = 0;
+ ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
+ if (len > max_len) {
+ ASSERT(false);
+ len = max_len;
+ }
+ strncpy(name, it->first.c_str(), len);
+ // To be on the safe side in case the source is longer than expected.
+ name[len - 1] = '\0';
+
+ len = it->second.length() + 1;
+ max_len = 0;
+ ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
+ if (len > max_len) {
+ ASSERT(false);
+ len = max_len;
+ }
+ strncpy(hashedName, it->second.c_str(), len);
+ // To be on the safe side in case the source is longer than expected.
+ hashedName[len - 1] = '\0';
+}
+
+void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TranslatorHLSL* translator = base->getAsTranslatorHLSL();
+ if (!translator) return;
+
+ switch(pname)
+ {
+ case SH_ACTIVE_UNIFORMS_ARRAY:
+ *params = (void*)&translator->getUniforms();
+ break;
+ case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY:
+ *params = (void*)&translator->getInterfaceBlocks();
+ break;
+ case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY:
+ *params = (void*)&translator->getOutputVariables();
+ break;
+ case SH_ACTIVE_ATTRIBUTES_ARRAY:
+ *params = (void*)&translator->getAttributes();
+ break;
+ case SH_ACTIVE_VARYINGS_ARRAY:
+ *params = (void*)&translator->getVaryings();
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+int ShCheckVariablesWithinPackingLimits(
+ int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize)
+{
+ if (varInfoArraySize == 0)
+ return 1;
+ ASSERT(varInfoArray);
+ TVariableInfoList variables;
+ for (size_t ii = 0; ii < varInfoArraySize; ++ii)
+ {
+ TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size);
+ variables.push_back(var);
+ }
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp
new file mode 100644
index 00000000000..aa5933d3e9a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp
@@ -0,0 +1,241 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Symbol table for parsing. Most functionaliy and main ideas
+// are documented in the header file.
+//
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4718)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+
+#include <stdio.h>
+#include <algorithm>
+
+int TSymbolTable::uniqueIdCounter = 0;
+
+//
+// Functions have buried pointers to delete.
+//
+TFunction::~TFunction()
+{
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
+}
+
+//
+// Symbol table levels are a map of pointers to symbols that have to be deleted.
+//
+TSymbolTableLevel::~TSymbolTableLevel()
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
+}
+
+bool TSymbolTableLevel::insert(const TString &name, TSymbol &symbol)
+{
+ symbol.setUniqueId(TSymbolTable::nextUniqueId());
+
+ // returning true means symbol was added to the table
+ tInsertResult result = level.insert(tLevelPair(name, &symbol));
+
+ return result.second;
+}
+
+bool TSymbolTableLevel::insert(TSymbol &symbol)
+{
+ return insert(symbol.getMangledName(), symbol);
+}
+
+TSymbol *TSymbolTableLevel::find(const TString &name) const
+{
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return 0;
+ else
+ return (*it).second;
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in operation. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToOperator(const char *name, TOperator op)
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ {
+ if ((*it).second->isFunction())
+ {
+ TFunction *function = static_cast<TFunction*>((*it).second);
+ if (function->getName() == name)
+ function->relateToOperator(op);
+ }
+ }
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in extension. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToExtension(const char *name, const TString &ext)
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ {
+ TSymbol *symbol = it->second;
+ if (symbol->getName() == name)
+ symbol->relateToExtension(ext);
+ }
+}
+
+TSymbol::TSymbol(const TSymbol &copyOf)
+{
+ name = NewPoolTString(copyOf.name->c_str());
+ uniqueId = copyOf.uniqueId;
+}
+
+TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope)
+{
+ int level = currentLevel();
+ TSymbol *symbol;
+
+ do
+ {
+ if (level == ESSL3_BUILTINS && shaderVersion != 300)
+ level--;
+ if (level == ESSL1_BUILTINS && shaderVersion != 100)
+ level--;
+
+ symbol = table[level]->find(name);
+ }
+ while (symbol == 0 && --level >= 0);
+
+ if (builtIn)
+ *builtIn = (level <= LAST_BUILTIN_LEVEL);
+ if (sameScope)
+ *sameScope = (level == currentLevel());
+
+ return symbol;
+}
+
+TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion)
+{
+ for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--)
+ {
+ if (level == ESSL3_BUILTINS && shaderVersion != 300)
+ level--;
+ if (level == ESSL1_BUILTINS && shaderVersion != 100)
+ level--;
+
+ TSymbol *symbol = table[level]->find(name);
+
+ if (symbol)
+ return symbol;
+ }
+
+ return 0;
+}
+
+TSymbolTable::~TSymbolTable()
+{
+ while (table.size() > 0)
+ pop();
+}
+
+void TSymbolTable::insertBuiltIn(
+ ESymbolLevel level, TType *rvalue, const char *name,
+ TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5)
+{
+ if (ptype1->getBasicType() == EbtGSampler2D)
+ {
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name,
+ new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name,
+ new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name,
+ new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5);
+ return;
+ }
+ if (ptype1->getBasicType() == EbtGSampler3D)
+ {
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name,
+ new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name,
+ new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name,
+ new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5);
+ return;
+ }
+ if (ptype1->getBasicType() == EbtGSamplerCube)
+ {
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name,
+ new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name,
+ new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name,
+ new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ return;
+ }
+ if (ptype1->getBasicType() == EbtGSampler2DArray)
+ {
+ bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
+ insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name,
+ new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name,
+ new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name,
+ new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ return;
+ }
+
+ TFunction *function = new TFunction(NewPoolTString(name), *rvalue);
+
+ TType *types[] = {ptype1, ptype2, ptype3, ptype4, ptype5};
+ for (size_t ii = 0; ii < sizeof(types) / sizeof(types[0]); ++ii)
+ {
+ if (types[ii])
+ {
+ TParameter param = {NULL, types[ii]};
+ function->addParameter(param);
+ }
+ }
+
+ insert(level, *function);
+}
+
+TPrecision TSymbolTable::getDefaultPrecision(TBasicType type)
+{
+ if (!SupportsPrecision(type))
+ return EbpUndefined;
+
+ // unsigned integers use the same precision as signed
+ TBasicType baseType = (type == EbtUInt) ? EbtInt : type;
+
+ int level = static_cast<int>(precisionStack.size()) - 1;
+ assert(level >= 0); // Just to be safe. Should not happen.
+ // If we dont find anything we return this. Should we error check this?
+ TPrecision prec = EbpUndefined;
+ while (level >= 0)
+ {
+ PrecisionStackLevel::iterator it = precisionStack[level]->find(baseType);
+ if (it != precisionStack[level]->end())
+ {
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.h b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h
new file mode 100644
index 00000000000..3f932a45432
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h
@@ -0,0 +1,431 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SYMBOL_TABLE_INCLUDED_
+#define _SYMBOL_TABLE_INCLUDED_
+
+//
+// Symbol table for parsing. Has these design characteristics:
+//
+// * Same symbol table can be used to compile many shaders, to preserve
+// effort of creating and loading with the large numbers of built-in
+// symbols.
+//
+// * Name mangling will be used to give each function a unique name
+// so that symbol table lookups are never ambiguous. This allows
+// a simpler symbol table structure.
+//
+// * Pushing and popping of scope, so symbol table will really be a stack
+// of symbol tables. Searched from the top, with new inserts going into
+// the top.
+//
+// * Constants: Compile time constant symbols will keep their values
+// in the symbol table. The parser can substitute constants at parse
+// time, including doing constant folding and constant propagation.
+//
+// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
+// are tracked in the intermediate representation, not the symbol table.
+//
+
+#include <assert.h>
+
+#include "common/angleutils.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/intermediate.h"
+
+// Symbol base class. (Can build functions or variables out of these...)
+class TSymbol
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TSymbol(const TString *n)
+ : uniqueId(0),
+ name(n)
+ {
+ }
+ virtual ~TSymbol()
+ {
+ // don't delete name, it's from the pool
+ }
+
+ const TString &getName() const
+ {
+ return *name;
+ }
+ virtual const TString &getMangledName() const
+ {
+ return getName();
+ }
+ virtual bool isFunction() const
+ {
+ return false;
+ }
+ virtual bool isVariable() const
+ {
+ return false;
+ }
+ void setUniqueId(int id)
+ {
+ uniqueId = id;
+ }
+ int getUniqueId() const
+ {
+ return uniqueId;
+ }
+ void relateToExtension(const TString &ext)
+ {
+ extension = ext;
+ }
+ const TString &getExtension() const
+ {
+ return extension;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TSymbol);
+
+ int uniqueId; // For real comparing during code generation
+ const TString *name;
+ TString extension;
+};
+
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class heirarchy for Constant variables;
+// Only one of int, bool, or float, (or none) is correct for
+// any particular use, but it's easy to do this way, and doesn't
+// seem worth having separate classes, and "getConst" can't simply return
+// different values for different types polymorphically, so this is
+// just simple and pragmatic.
+class TVariable : public TSymbol
+{
+ public:
+ TVariable(const TString *name, const TType &t, bool uT = false)
+ : TSymbol(name),
+ type(t),
+ userType(uT),
+ unionArray(0)
+ {
+ }
+ virtual ~TVariable()
+ {
+ }
+ virtual bool isVariable() const
+ {
+ return true;
+ }
+ TType &getType()
+ {
+ return type;
+ }
+ const TType &getType() const
+ {
+ return type;
+ }
+ bool isUserType() const
+ {
+ return userType;
+ }
+ void setQualifier(TQualifier qualifier)
+ {
+ type.setQualifier(qualifier);
+ }
+
+ ConstantUnion *getConstPointer()
+ {
+ if (!unionArray)
+ unionArray = new ConstantUnion[type.getObjectSize()];
+
+ return unionArray;
+ }
+
+ ConstantUnion *getConstPointer() const
+ {
+ return unionArray;
+ }
+
+ void shareConstPointer(ConstantUnion *constArray)
+ {
+ if (unionArray == constArray)
+ return;
+
+ delete[] unionArray;
+ unionArray = constArray;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TVariable);
+
+ TType type;
+ bool userType;
+ // we are assuming that Pool Allocator will free the memory
+ // allocated to unionArray when this object is destroyed.
+ ConstantUnion *unionArray;
+};
+
+// The function sub-class of symbols and the parser will need to
+// share this definition of a function parameter.
+struct TParameter
+{
+ TString *name;
+ TType *type;
+};
+
+// The function sub-class of a symbol.
+class TFunction : public TSymbol
+{
+ public:
+ TFunction(TOperator o)
+ : TSymbol(0),
+ returnType(TType(EbtVoid, EbpUndefined)),
+ op(o),
+ defined(false)
+ {
+ }
+ TFunction(const TString *name, TType &retType, TOperator tOp = EOpNull)
+ : TSymbol(name),
+ returnType(retType),
+ mangledName(TFunction::mangleName(*name)),
+ op(tOp),
+ defined(false)
+ {
+ }
+ virtual ~TFunction();
+ virtual bool isFunction() const
+ {
+ return true;
+ }
+
+ static TString mangleName(const TString &name)
+ {
+ return name + '(';
+ }
+ static TString unmangleName(const TString &mangledName)
+ {
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+ }
+
+ void addParameter(TParameter &p)
+ {
+ parameters.push_back(p);
+ mangledName = mangledName + p.type->getMangledName();
+ }
+
+ const TString &getMangledName() const
+ {
+ return mangledName;
+ }
+ const TType &getReturnType() const
+ {
+ return returnType;
+ }
+
+ void relateToOperator(TOperator o)
+ {
+ op = o;
+ }
+ TOperator getBuiltInOp() const
+ {
+ return op;
+ }
+
+ void setDefined()
+ {
+ defined = true;
+ }
+ bool isDefined()
+ {
+ return defined;
+ }
+
+ size_t getParamCount() const
+ {
+ return parameters.size();
+ }
+ const TParameter &getParam(size_t i) const
+ {
+ return parameters[i];
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TFunction);
+
+ typedef TVector<TParameter> TParamList;
+ TParamList parameters;
+ TType returnType;
+ TString mangledName;
+ TOperator op;
+ bool defined;
+};
+
+// Interface block name sub-symbol
+class TInterfaceBlockName : public TSymbol
+{
+ public:
+ TInterfaceBlockName(const TString *name)
+ : TSymbol(name)
+ {
+ }
+
+ virtual ~TInterfaceBlockName()
+ {
+ }
+};
+
+class TSymbolTableLevel
+{
+ public:
+ typedef TMap<TString, TSymbol *> tLevel;
+ typedef tLevel::const_iterator const_iterator;
+ typedef const tLevel::value_type tLevelPair;
+ typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+ TSymbolTableLevel()
+ {
+ }
+ ~TSymbolTableLevel();
+
+ bool insert(const TString &name, TSymbol &symbol);
+ bool insert(TSymbol &symbol);
+
+ TSymbol *find(const TString &name) const;
+
+ void relateToOperator(const char *name, TOperator op);
+ void relateToExtension(const char *name, const TString &ext);
+
+ protected:
+ tLevel level;
+ static int uniqueId; // for unique identification in code generation
+};
+
+enum ESymbolLevel
+{
+ COMMON_BUILTINS = 0,
+ ESSL1_BUILTINS = 1,
+ ESSL3_BUILTINS = 2,
+ LAST_BUILTIN_LEVEL = ESSL3_BUILTINS,
+ GLOBAL_LEVEL = 3
+};
+
+class TSymbolTable
+{
+ public:
+ TSymbolTable()
+ {
+ // The symbol table cannot be used until push() is called, but
+ // the lack of an initial call to push() can be used to detect
+ // that the symbol table has not been preloaded with built-ins.
+ }
+
+ ~TSymbolTable();
+
+ // When the symbol table is initialized with the built-ins, there should
+ // 'push' calls, so that built-ins are at level 0 and the shader
+ // globals are at level 1.
+ bool isEmpty()
+ {
+ return table.empty();
+ }
+ bool atBuiltInLevel()
+ {
+ return currentLevel() <= LAST_BUILTIN_LEVEL;
+ }
+ bool atGlobalLevel()
+ {
+ return currentLevel() <= GLOBAL_LEVEL;
+ }
+ void push()
+ {
+ table.push_back(new TSymbolTableLevel);
+ precisionStack.push_back(new PrecisionStackLevel);
+ }
+
+ void pop()
+ {
+ delete table.back();
+ table.pop_back();
+
+ delete precisionStack.back();
+ precisionStack.pop_back();
+ }
+
+ bool declare(TSymbol &symbol)
+ {
+ return insert(currentLevel(), symbol);
+ }
+
+ bool insert(ESymbolLevel level, TSymbol &symbol)
+ {
+ return table[level]->insert(symbol);
+ }
+
+ bool insertConstInt(ESymbolLevel level, const char *name, int value)
+ {
+ TVariable *constant = new TVariable(
+ NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
+ constant->getConstPointer()->setIConst(value);
+ return insert(level, *constant);
+ }
+
+ void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name,
+ TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0,
+ TType *ptype4 = 0, TType *ptype5 = 0);
+
+ TSymbol *find(const TString &name, int shaderVersion,
+ bool *builtIn = NULL, bool *sameScope = NULL);
+ TSymbol *findBuiltIn(const TString &name, int shaderVersion);
+
+ TSymbolTableLevel *getOuterLevel()
+ {
+ assert(currentLevel() >= 1);
+ return table[currentLevel() - 1];
+ }
+
+ void relateToOperator(ESymbolLevel level, const char *name, TOperator op)
+ {
+ table[level]->relateToOperator(name, op);
+ }
+ void relateToExtension(ESymbolLevel level, const char *name, const TString &ext)
+ {
+ table[level]->relateToExtension(name, ext);
+ }
+ void dump(TInfoSink &infoSink) const;
+
+ bool setDefaultPrecision(const TPublicType &type, TPrecision prec)
+ {
+ if (!SupportsPrecision(type.type))
+ return false;
+ if (type.isAggregate())
+ return false; // Not allowed to set for aggregate types
+ int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
+ // Uses map operator [], overwrites the current value
+ (*precisionStack[indexOfLastElement])[type.type] = prec;
+ return true;
+ }
+
+ // Searches down the precisionStack for a precision qualifier
+ // for the specified TBasicType
+ TPrecision getDefaultPrecision(TBasicType type);
+
+ static int nextUniqueId()
+ {
+ return ++uniqueIdCounter;
+ }
+
+ private:
+ ESymbolLevel currentLevel() const
+ {
+ return static_cast<ESymbolLevel>(table.size() - 1);
+ }
+
+ std::vector<TSymbolTableLevel *> table;
+ typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
+ std::vector< PrecisionStackLevel *> precisionStack;
+
+ static int uniqueIdCounter;
+};
+
+#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp
new file mode 100644
index 00000000000..c956e29c5be
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorESSL.h"
+
+#include "compiler/translator/OutputESSL.h"
+
+TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec, SH_ESSL_OUTPUT) {
+}
+
+void TranslatorESSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior();
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, getShaderType() == SH_FRAGMENT_SHADER);
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion());
+ root->traverse(&outputESSL);
+}
+
+void TranslatorESSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
+ iter != extensionBehavior.end(); ++iter) {
+ if (iter->second != EBhUndefined) {
+ sink << "#extension " << iter->first << " : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h
new file mode 100644
index 00000000000..e18f3c25ec8
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORESSL_H_
+#define COMPILER_TRANSLATORESSL_H_
+
+#include "compiler/translator/ShHandle.h"
+
+class TranslatorESSL : public TCompiler {
+public:
+ TranslatorESSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATORESSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp
new file mode 100644
index 00000000000..749d8377f0c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorGLSL.h"
+
+#include "compiler/translator/OutputGLSL.h"
+#include "compiler/translator/VersionGLSL.h"
+
+static void writeVersion(ShShaderType type, TIntermNode* root,
+ TInfoSinkBase& sink) {
+ TVersionGLSL versionGLSL(type);
+ root->traverse(&versionGLSL);
+ int version = versionGLSL.getVersion();
+ // We need to write version directive only if it is greater than 110.
+ // If there is no version directive in the shader, 110 is implied.
+ if (version > 110) {
+ sink << "#version " << version << "\n";
+ }
+}
+
+TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec, SH_GLSL_OUTPUT) {
+}
+
+void TranslatorGLSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(getShaderType(), root, sink);
+
+ // Write extension behaviour as needed
+ writeExtensionBehavior();
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, false);
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion());
+ root->traverse(&outputGLSL);
+}
+
+void TranslatorGLSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
+ iter != extensionBehavior.end(); ++iter) {
+ if (iter->second == EBhUndefined)
+ continue;
+
+ // For GLSL output, we don't need to emit most extensions explicitly,
+ // but some we need to translate.
+ if (iter->first == "GL_EXT_shader_texture_lod") {
+ sink << "#extension GL_ARB_shader_texture_lod : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h
new file mode 100644
index 00000000000..1e16b2605e4
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORGLSL_H_
+#define COMPILER_TRANSLATORGLSL_H_
+
+#include "compiler/translator/ShHandle.h"
+
+class TranslatorGLSL : public TCompiler {
+public:
+ TranslatorGLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATORGLSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp
new file mode 100644
index 00000000000..da6f9801ad0
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/TranslatorHLSL.h"
+
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/OutputHLSL.h"
+
+TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{
+}
+
+void TranslatorHLSL::translate(TIntermNode *root)
+{
+ TParseContext& parseContext = *GetGlobalParseContext();
+ sh::OutputHLSL outputHLSL(parseContext, getResources(), getOutputType());
+
+ outputHLSL.output();
+
+ mActiveUniforms = outputHLSL.getUniforms();
+ mActiveInterfaceBlocks = outputHLSL.getInterfaceBlocks();
+ mActiveOutputVariables = outputHLSL.getOutputVariables();
+ mActiveAttributes = outputHLSL.getAttributes();
+ mActiveVaryings = outputHLSL.getVaryings();
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h
new file mode 100644
index 00000000000..8b16587b6b1
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATORHLSL_H_
+
+#include "compiler/translator/ShHandle.h"
+#include "common/shadervars.h"
+
+class TranslatorHLSL : public TCompiler {
+public:
+ TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+
+ virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; }
+ const std::vector<gl::Uniform> &getUniforms() { return mActiveUniforms; }
+ const std::vector<gl::InterfaceBlock> &getInterfaceBlocks() const { return mActiveInterfaceBlocks; }
+ const std::vector<gl::Attribute> &getOutputVariables() { return mActiveOutputVariables; }
+ const std::vector<gl::Attribute> &getAttributes() { return mActiveAttributes; }
+ const std::vector<gl::Varying> &getVaryings() { return mActiveVaryings; }
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+ std::vector<gl::Uniform> mActiveUniforms;
+ std::vector<gl::InterfaceBlock> mActiveInterfaceBlocks;
+ std::vector<gl::Attribute> mActiveOutputVariables;
+ std::vector<gl::Attribute> mActiveAttributes;
+ std::vector<gl::Varying> mActiveVaryings;
+};
+
+#endif // COMPILER_TRANSLATORHLSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/Types.cpp b/chromium/third_party/angle/src/compiler/translator/Types.cpp
new file mode 100644
index 00000000000..4763920f86e
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Types.cpp
@@ -0,0 +1,250 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4718)
+#endif
+
+#include "compiler/translator/Types.h"
+
+#include <algorithm>
+#include <climits>
+
+TType::TType(const TPublicType &p)
+ : type(p.type), precision(p.precision), qualifier(p.qualifier), layoutQualifier(p.layoutQualifier),
+ primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize),
+ interfaceBlock(0), structure(0)
+{
+ if (p.userDef)
+ structure = p.userDef->getStruct();
+}
+
+bool TType::equals(const TType &other) const
+{
+ if (type != other.type || precision != other.precision ||
+ primarySize != other.primarySize || secondarySize != other.secondarySize ||
+ array != other.array || (array && arraySize != other.arraySize) ||
+ interfaceBlock != other.interfaceBlock || structure != other.structure)
+ {
+ return false;
+ }
+ if (interfaceBlock && !interfaceBlock->equals(*(other.interfaceBlock)))
+ return false;
+ if (structure && !structure->equals(*(other.structure)))
+ return false;
+ return true;
+}
+
+bool TField::equals(const TField &other) const
+{
+ ASSERT(mType && mName);
+ ASSERT(other.mType && other.mName);
+ return mType->equals(*(other.mType)) && *mName == *(other.mName);
+}
+
+bool TFieldListCollection::equals(const TFieldListCollection &other) const
+{
+ ASSERT(mName && mFields);
+ ASSERT(other.mName && other.mFields);
+ if (*mName != *(other.mName))
+ return false;
+ if (mFields->size() != other.mFields->size())
+ return false;
+ for (size_t ii = 0; ii < mFields->size(); ++ii)
+ {
+ ASSERT((*mFields)[ii] && (*(other.mFields))[ii]);
+ if (!(*mFields)[ii]->equals(*((*(other.mFields))[ii])))
+ return false;
+ }
+ return true;
+}
+
+bool TStructure::equals(const TStructure &other) const
+{
+ return TFieldListCollection::equals(other);
+}
+
+bool TInterfaceBlock::equals(const TInterfaceBlock &other) const
+{
+ if (!TFieldListCollection::equals(other))
+ return false;
+ // TODO(zmo): do we need to consider mBlockStorage and mMatrixPacking?
+ return mArraySize == other.mArraySize;
+}
+
+//
+// Recursively generate mangled names.
+//
+TString TType::buildMangledName() const
+{
+ TString mangledName;
+ if (isMatrix())
+ mangledName += 'm';
+ else if (isVector())
+ mangledName += 'v';
+
+ switch (type)
+ {
+ case EbtFloat:
+ mangledName += 'f';
+ break;
+ case EbtInt:
+ mangledName += 'i';
+ break;
+ case EbtUInt:
+ mangledName += 'u';
+ break;
+ case EbtBool:
+ mangledName += 'b';
+ break;
+ case EbtSampler2D:
+ mangledName += "s2";
+ break;
+ case EbtSampler3D:
+ mangledName += "s3";
+ break;
+ case EbtSamplerCube:
+ mangledName += "sC";
+ break;
+ case EbtSampler2DArray:
+ mangledName += "s2a";
+ break;
+ case EbtSamplerExternalOES:
+ mangledName += "sext";
+ break;
+ case EbtSampler2DRect:
+ mangledName += "s2r";
+ break;
+ case EbtISampler2D:
+ mangledName += "is2";
+ break;
+ case EbtISampler3D:
+ mangledName += "is3";
+ break;
+ case EbtISamplerCube:
+ mangledName += "isC";
+ break;
+ case EbtISampler2DArray:
+ mangledName += "is2a";
+ break;
+ case EbtUSampler2D:
+ mangledName += "us2";
+ break;
+ case EbtUSampler3D:
+ mangledName += "us3";
+ break;
+ case EbtUSamplerCube:
+ mangledName += "usC";
+ break;
+ case EbtUSampler2DArray:
+ mangledName += "us2a";
+ break;
+ case EbtSampler2DShadow:
+ mangledName += "s2s";
+ break;
+ case EbtSamplerCubeShadow:
+ mangledName += "sCs";
+ break;
+ case EbtSampler2DArrayShadow:
+ mangledName += "s2as";
+ break;
+ case EbtStruct:
+ mangledName += structure->mangledName();
+ break;
+ case EbtInterfaceBlock:
+ mangledName += interfaceBlock->mangledName();
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ if (isMatrix())
+ {
+ mangledName += static_cast<char>('0' + getCols());
+ mangledName += static_cast<char>('x');
+ mangledName += static_cast<char>('0' + getRows());
+ }
+ else
+ {
+ mangledName += static_cast<char>('0' + getNominalSize());
+ }
+
+ if (isArray())
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+ return mangledName;
+}
+
+size_t TType::getObjectSize() const
+{
+ size_t totalSize;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = structure->objectSize();
+ else
+ totalSize = primarySize * secondarySize;
+
+ if (isArray())
+ {
+ size_t arraySize = getArraySize();
+ if (arraySize > INT_MAX / totalSize)
+ totalSize = INT_MAX;
+ else
+ totalSize *= arraySize;
+ }
+
+ return totalSize;
+}
+
+bool TStructure::containsArrays() const
+{
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ const TType *fieldType = (*mFields)[i]->type();
+ if (fieldType->isArray() || fieldType->isStructureContainingArrays())
+ return true;
+ }
+ return false;
+}
+
+TString TFieldListCollection::buildMangledName() const
+{
+ TString mangledName(mangledNamePrefix());
+ mangledName += *mName;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ mangledName += '-';
+ mangledName += (*mFields)[i]->type()->getMangledName();
+ }
+ return mangledName;
+}
+
+size_t TFieldListCollection::calculateObjectSize() const
+{
+ size_t size = 0;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
+ if (fieldSize > INT_MAX - size)
+ size = INT_MAX;
+ else
+ size += fieldSize;
+ }
+ return size;
+}
+
+int TStructure::calculateDeepestNesting() const
+{
+ int maxNesting = 0;
+ for (size_t i = 0; i < mFields->size(); ++i)
+ maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
+ return 1 + maxNesting;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/Types.h b/chromium/third_party/angle/src/compiler/translator/Types.h
new file mode 100644
index 00000000000..76297202a56
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/Types.h
@@ -0,0 +1,586 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "common/angleutils.h"
+
+#include "compiler/translator/BaseTypes.h"
+#include "compiler/translator/Common.h"
+#include "compiler/translator/compilerdebug.h"
+
+struct TPublicType;
+class TType;
+class TSymbol;
+
+class TField
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TField(TType *type, TString *name, const TSourceLoc &line)
+ : mType(type),
+ mName(name),
+ mLine(line)
+ {
+ }
+
+ // TODO(alokp): We should only return const type.
+ // Fix it by tweaking grammar.
+ TType *type()
+ {
+ return mType;
+ }
+ const TType *type() const
+ {
+ return mType;
+ }
+
+ const TString &name() const
+ {
+ return *mName;
+ }
+ const TSourceLoc &line() const
+ {
+ return mLine;
+ }
+
+ bool equals(const TField &other) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TField);
+ TType *mType;
+ TString *mName;
+ TSourceLoc mLine;
+};
+
+typedef TVector<TField *> TFieldList;
+inline TFieldList *NewPoolTFieldList()
+{
+ void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList));
+ return new(memory) TFieldList;
+}
+
+class TFieldListCollection
+{
+ public:
+ const TString &name() const
+ {
+ return *mName;
+ }
+ const TFieldList &fields() const
+ {
+ return *mFields;
+ }
+
+ const TString &mangledName() const
+ {
+ if (mMangledName.empty())
+ mMangledName = buildMangledName();
+ return mMangledName;
+ }
+ size_t objectSize() const
+ {
+ if (mObjectSize == 0)
+ mObjectSize = calculateObjectSize();
+ return mObjectSize;
+ };
+
+ protected:
+ TFieldListCollection(const TString *name, TFieldList *fields)
+ : mName(name),
+ mFields(fields),
+ mObjectSize(0)
+ {
+ }
+ TString buildMangledName() const;
+ size_t calculateObjectSize() const;
+ virtual TString mangledNamePrefix() const = 0;
+
+ bool equals(const TFieldListCollection &other) const;
+
+ const TString *mName;
+ TFieldList *mFields;
+
+ mutable TString mMangledName;
+ mutable size_t mObjectSize;
+};
+
+// May also represent interface blocks
+class TStructure : public TFieldListCollection
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TStructure(const TString *name, TFieldList *fields)
+ : TFieldListCollection(name, fields),
+ mDeepestNesting(0),
+ mUniqueId(0)
+ {
+ }
+
+ int deepestNesting() const
+ {
+ if (mDeepestNesting == 0)
+ mDeepestNesting = calculateDeepestNesting();
+ return mDeepestNesting;
+ }
+ bool containsArrays() const;
+
+ bool equals(const TStructure &other) const;
+
+ void setUniqueId(int uniqueId)
+ {
+ mUniqueId = uniqueId;
+ }
+
+ int uniqueId() const
+ {
+ ASSERT(mUniqueId != 0);
+ return mUniqueId;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TStructure);
+ virtual TString mangledNamePrefix() const
+ {
+ return "struct-";
+ }
+ int calculateDeepestNesting() const;
+
+ mutable int mDeepestNesting;
+ int mUniqueId;
+};
+
+class TInterfaceBlock : public TFieldListCollection
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName,
+ int arraySize, const TLayoutQualifier &layoutQualifier)
+ : TFieldListCollection(name, fields),
+ mInstanceName(instanceName),
+ mArraySize(arraySize),
+ mBlockStorage(layoutQualifier.blockStorage),
+ mMatrixPacking(layoutQualifier.matrixPacking)
+ {
+ }
+
+ const TString &instanceName() const
+ {
+ return *mInstanceName;
+ }
+ bool hasInstanceName() const
+ {
+ return mInstanceName != NULL;
+ }
+ bool isArray() const
+ {
+ return mArraySize > 0;
+ }
+ int arraySize() const
+ {
+ return mArraySize;
+ }
+ TLayoutBlockStorage blockStorage() const
+ {
+ return mBlockStorage;
+ }
+ TLayoutMatrixPacking matrixPacking() const
+ {
+ return mMatrixPacking;
+ }
+
+ bool equals(const TInterfaceBlock &other) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TInterfaceBlock);
+ virtual TString mangledNamePrefix() const
+ {
+ return "iblock-";
+ }
+
+ const TString *mInstanceName; // for interface block instance names
+ int mArraySize; // 0 if not an array
+ TLayoutBlockStorage mBlockStorage;
+ TLayoutMatrixPacking mMatrixPacking;
+};
+
+//
+// Base class for things that have a type.
+//
+class TType
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TType()
+ {
+ }
+ TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1)
+ : type(t), precision(EbpUndefined), qualifier(EvqGlobal),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(ps), secondarySize(ss), array(false), arraySize(0),
+ interfaceBlock(0), structure(0)
+ {
+ }
+ TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary,
+ unsigned char ps = 1, unsigned char ss = 1, bool a = false)
+ : type(t), precision(p), qualifier(q),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(ps), secondarySize(ss), array(a), arraySize(0),
+ interfaceBlock(0), structure(0)
+ {
+ }
+ explicit TType(const TPublicType &p);
+ TType(TStructure *userDef, TPrecision p = EbpUndefined)
+ : type(EbtStruct), precision(p), qualifier(EvqTemporary),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(1), secondarySize(1), array(false), arraySize(0),
+ interfaceBlock(0), structure(userDef)
+ {
+ }
+ TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
+ TLayoutQualifier layoutQualifierIn, int arraySizeIn)
+ : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
+ layoutQualifier(layoutQualifierIn),
+ primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn),
+ interfaceBlock(interfaceBlockIn), structure(0)
+ {
+ }
+
+ TBasicType getBasicType() const
+ {
+ return type;
+ }
+ void setBasicType(TBasicType t)
+ {
+ type = t;
+ }
+
+ TPrecision getPrecision() const
+ {
+ return precision;
+ }
+ void setPrecision(TPrecision p)
+ {
+ precision = p;
+ }
+
+ TQualifier getQualifier() const
+ {
+ return qualifier;
+ }
+ void setQualifier(TQualifier q)
+ {
+ qualifier = q;
+ }
+
+ TLayoutQualifier getLayoutQualifier() const
+ {
+ return layoutQualifier;
+ }
+ void setLayoutQualifier(TLayoutQualifier lq)
+ {
+ layoutQualifier = lq;
+ }
+
+ int getNominalSize() const
+ {
+ return primarySize;
+ }
+ int getSecondarySize() const
+ {
+ return secondarySize;
+ }
+ int getCols() const
+ {
+ ASSERT(isMatrix());
+ return primarySize;
+ }
+ int getRows() const
+ {
+ ASSERT(isMatrix());
+ return secondarySize;
+ }
+ void setPrimarySize(unsigned char ps)
+ {
+ primarySize = ps;
+ }
+ void setSecondarySize(unsigned char ss)
+ {
+ secondarySize = ss;
+ }
+
+ // Full size of single instance of type
+ size_t getObjectSize() const;
+
+ bool isMatrix() const
+ {
+ return primarySize > 1 && secondarySize > 1;
+ }
+ bool isArray() const
+ {
+ return array ? true : false;
+ }
+ int getArraySize() const
+ {
+ return arraySize;
+ }
+ void setArraySize(int s)
+ {
+ array = true;
+ arraySize = s;
+ }
+ void clearArrayness()
+ {
+ array = false;
+ arraySize = 0;
+ }
+
+ TInterfaceBlock *getInterfaceBlock() const
+ {
+ return interfaceBlock;
+ }
+ void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn)
+ {
+ interfaceBlock = interfaceBlockIn;
+ }
+ bool isInterfaceBlock() const
+ {
+ return type == EbtInterfaceBlock;
+ }
+
+ bool isVector() const
+ {
+ return primarySize > 1 && secondarySize == 1;
+ }
+ bool isScalar() const
+ {
+ return primarySize == 1 && secondarySize == 1 && !structure;
+ }
+ bool isScalarInt() const
+ {
+ return isScalar() && (type == EbtInt || type == EbtUInt);
+ }
+
+ TStructure *getStruct() const
+ {
+ return structure;
+ }
+ void setStruct(TStructure *s)
+ {
+ structure = s;
+ }
+
+ const TString &getMangledName()
+ {
+ if (mangled.empty())
+ {
+ mangled = buildMangledName();
+ mangled += ';';
+ }
+
+ return mangled;
+ }
+
+ // This is different from operator== as we also compare
+ // precision here.
+ bool equals(const TType &other) const;
+
+ bool sameElementType(const TType &right) const
+ {
+ return type == right.type &&
+ primarySize == right.primarySize &&
+ secondarySize == right.secondarySize &&
+ structure == right.structure;
+ }
+ bool operator==(const TType &right) const
+ {
+ return type == right.type &&
+ primarySize == right.primarySize &&
+ secondarySize == right.secondarySize &&
+ array == right.array && (!array || arraySize == right.arraySize) &&
+ structure == right.structure;
+ // don't check the qualifier, it's not ever what's being sought after
+ }
+ bool operator!=(const TType &right) const
+ {
+ return !operator==(right);
+ }
+ bool operator<(const TType &right) const
+ {
+ if (type != right.type)
+ return type < right.type;
+ if (primarySize != right.primarySize)
+ return primarySize < right.primarySize;
+ if (secondarySize != right.secondarySize)
+ return secondarySize < right.secondarySize;
+ if (array != right.array)
+ return array < right.array;
+ if (arraySize != right.arraySize)
+ return arraySize < right.arraySize;
+ if (structure != right.structure)
+ return structure < right.structure;
+
+ return false;
+ }
+
+ const char *getBasicString() const
+ {
+ return ::getBasicString(type);
+ }
+ const char *getPrecisionString() const
+ {
+ return ::getPrecisionString(precision);
+ }
+ const char *getQualifierString() const
+ {
+ return ::getQualifierString(qualifier);
+ }
+ TString getCompleteString() const;
+
+ // If this type is a struct, returns the deepest struct nesting of
+ // any field in the struct. For example:
+ // struct nesting1 {
+ // vec4 position;
+ // };
+ // struct nesting2 {
+ // nesting1 field1;
+ // vec4 field2;
+ // };
+ // For type "nesting2", this method would return 2 -- the number
+ // of structures through which indirection must occur to reach the
+ // deepest field (nesting2.field1.position).
+ int getDeepestStructNesting() const
+ {
+ return structure ? structure->deepestNesting() : 0;
+ }
+
+ bool isStructureContainingArrays() const
+ {
+ return structure ? structure->containsArrays() : false;
+ }
+
+ protected:
+ TString buildMangledName() const;
+ size_t getStructSize() const;
+ void computeDeepestStructNesting();
+
+ TBasicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TLayoutQualifier layoutQualifier;
+ unsigned char primarySize; // size of vector or cols matrix
+ unsigned char secondarySize; // rows of a matrix
+ bool array;
+ int arraySize;
+
+ // 0 unless this is an interface block, or interface block member variable
+ TInterfaceBlock *interfaceBlock;
+
+ // 0 unless this is a struct
+ TStructure *structure;
+
+ mutable TString mangled;
+};
+
+//
+// This is a workaround for a problem with the yacc stack, It can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else. Pointers
+// could be used, but also trying to avoid lots of memory management overhead.
+//
+// Not as bad as it looks, there is no actual assumption that the fields
+// match up or are name the same or anything like that.
+//
+struct TPublicType
+{
+ TBasicType type;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TPrecision precision;
+ unsigned char primarySize; // size of vector or cols of matrix
+ unsigned char secondarySize; // rows of matrix
+ bool array;
+ int arraySize;
+ TType *userDef;
+ TSourceLoc line;
+
+ void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
+ {
+ type = bt;
+ layoutQualifier = TLayoutQualifier::create();
+ qualifier = q;
+ precision = EbpUndefined;
+ primarySize = 1;
+ secondarySize = 1;
+ array = false;
+ arraySize = 0;
+ userDef = 0;
+ line = ln;
+ }
+
+ void setAggregate(unsigned char size)
+ {
+ primarySize = size;
+ }
+
+ void setMatrix(unsigned char c, unsigned char r)
+ {
+ ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4);
+ primarySize = c;
+ secondarySize = r;
+ }
+
+ void setArray(bool a, int s = 0)
+ {
+ array = a;
+ arraySize = s;
+ }
+
+ bool isStructureContainingArrays() const
+ {
+ if (!userDef)
+ {
+ return false;
+ }
+
+ return userDef->isStructureContainingArrays();
+ }
+
+ bool isMatrix() const
+ {
+ return primarySize > 1 && secondarySize > 1;
+ }
+
+ bool isVector() const
+ {
+ return primarySize > 1 && secondarySize == 1;
+ }
+
+ int getCols() const
+ {
+ ASSERT(isMatrix());
+ return primarySize;
+ }
+
+ int getRows() const
+ {
+ ASSERT(isMatrix());
+ return secondarySize;
+ }
+
+ int getNominalSize() const
+ {
+ return primarySize;
+ }
+
+ bool isAggregate() const
+ {
+ return array || isMatrix() || isVector();
+ }
+};
+
+#endif // _TYPES_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp
new file mode 100644
index 00000000000..b7826119aea
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp
@@ -0,0 +1,184 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#include "compiler/translator/UnfoldShortCircuit.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/OutputHLSL.h"
+
+namespace sh
+{
+UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
+{
+ mTemporaryIndex = 0;
+}
+
+void UnfoldShortCircuit::traverse(TIntermNode *node)
+{
+ int rewindIndex = mTemporaryIndex;
+ node->traverse(this);
+ mTemporaryIndex = rewindIndex;
+}
+
+bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ // If our right node doesn't have side effects, we know we don't need to unfold this
+ // expression: there will be no short-circuiting side effects to avoid
+ // (note: unfolding doesn't depend on the left node -- it will always be evaluated)
+ if (!node->getRight()->hasSideEffects())
+ {
+ return true;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;",
+ // and then further simplifies down to "bool s = x; if(!s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if (!s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ case EOpLogicalAnd:
+ // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;",
+ // and then further simplifies down to "bool s = x; if(s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if (s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ if (node->usesTernaryOperator())
+ {
+ int i = mTemporaryIndex;
+
+ out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(this);
+ out << "if (";
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(mOutputHLSL);
+ out << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n"
+ "else\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+
+ return false;
+}
+
+bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
+{
+ int rewindIndex = mTemporaryIndex;
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ mTemporaryIndex = rewindIndex;
+
+ return false;
+}
+
+int UnfoldShortCircuit::getNextTemporaryIndex()
+{
+ return mTemporaryIndex++;
+}
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h
new file mode 100644
index 00000000000..1e416bc04c1
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements
+//
+
+#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_UNFOLDSHORTCIRCUIT_H_
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/ParseContext.h"
+
+namespace sh
+{
+class OutputHLSL;
+
+class UnfoldShortCircuit : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL);
+
+ void traverse(TIntermNode *node);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitSelection(Visit visit, TIntermSelection *node);
+ bool visitLoop(Visit visit, TIntermLoop *node);
+
+ int getNextTemporaryIndex();
+
+ protected:
+ TParseContext &mContext;
+ OutputHLSL *const mOutputHLSL;
+
+ int mTemporaryIndex;
+};
+}
+
+#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp
new file mode 100644
index 00000000000..29c4397d561
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/UnfoldShortCircuitAST.h"
+
+namespace
+{
+
+// "x || y" is equivalent to "x ? true : y".
+TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
+{
+ const TType boolType(EbtBool, EbpUndefined);
+ ConstantUnion *u = new ConstantUnion;
+ u->setBConst(true);
+ TIntermConstantUnion *trueNode = new TIntermConstantUnion(
+ u, TType(EbtBool, EbpUndefined, EvqConst, 1));
+ return new TIntermSelection(x, trueNode, y, boolType);
+}
+
+// "x && y" is equivalent to "x ? y : false".
+TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
+{
+ const TType boolType(EbtBool, EbpUndefined);
+ ConstantUnion *u = new ConstantUnion;
+ u->setBConst(false);
+ TIntermConstantUnion *falseNode = new TIntermConstantUnion(
+ u, TType(EbtBool, EbpUndefined, EvqConst, 1));
+ return new TIntermSelection(x, y, falseNode, boolType);
+}
+
+} // namespace anonymous
+
+bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TIntermSelection *replacement = NULL;
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ replacement = UnfoldOR(node->getLeft(), node->getRight());
+ break;
+ case EOpLogicalAnd:
+ replacement = UnfoldAND(node->getLeft(), node->getRight());
+ break;
+ default:
+ break;
+ }
+ if (replacement)
+ {
+ replacements.push_back(
+ NodeUpdateEntry(getParentNode(), node, replacement));
+ }
+ return true;
+}
+
+void UnfoldShortCircuitAST::updateTree()
+{
+ for (size_t ii = 0; ii < replacements.size(); ++ii)
+ {
+ const NodeUpdateEntry& entry = replacements[ii];
+ ASSERT(entry.parent);
+ bool replaced = entry.parent->replaceChildNode(
+ entry.original, entry.replacement);
+ ASSERT(replaced);
+
+ // In AST traversing, a parent is visited before its children.
+ // After we replace a node, if an immediate child is to
+ // be replaced, we need to make sure we don't update the replaced
+ // node; instead, we update the replacement node.
+ for (size_t jj = ii + 1; jj < replacements.size(); ++jj)
+ {
+ NodeUpdateEntry& entry2 = replacements[jj];
+ if (entry2.parent == entry.original)
+ entry2.parent = entry.replacement;
+ }
+ }
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h
new file mode 100644
index 00000000000..24c14a60e37
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitAST is an AST traverser to replace short-circuiting
+// operations with ternary operations.
+//
+
+#ifndef COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_
+#define COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_
+
+#include "common/angleutils.h"
+#include "compiler/translator/intermediate.h"
+
+// This traverser identifies all the short circuit binary nodes that need to
+// be replaced, and creates the corresponding replacement nodes. However,
+// the actual replacements happen after the traverse through updateTree().
+
+class UnfoldShortCircuitAST : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitAST() { }
+
+ virtual bool visitBinary(Visit visit, TIntermBinary *);
+
+ void updateTree();
+
+ private:
+ struct NodeUpdateEntry
+ {
+ NodeUpdateEntry(TIntermNode *_parent,
+ TIntermNode *_original,
+ TIntermNode *_replacement)
+ : parent(_parent),
+ original(_original),
+ replacement(_replacement) {}
+
+ TIntermNode *parent;
+ TIntermNode *original;
+ TIntermNode *replacement;
+ };
+
+ // During traversing, save all the replacements that need to happen;
+ // then replace them by calling updateNodes().
+ std::vector<NodeUpdateEntry> replacements;
+
+ DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST);
+};
+
+#endif // COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp
new file mode 100644
index 00000000000..e96a777cee3
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp
@@ -0,0 +1,469 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateLimitations.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/ParseContext.h"
+
+namespace
+{
+
+// Traverses a node to check if it represents a constant index expression.
+// Definition:
+// constant-index-expressions are a superset of constant-expressions.
+// Constant-index-expressions can include loop indices as defined in
+// GLSL ES 1.0 spec, Appendix A, section 4.
+// The following are constant-index-expressions:
+// - Constant expressions
+// - Loop indices as defined in section 4
+// - Expressions composed of both of the above
+class ValidateConstIndexExpr : public TIntermTraverser
+{
+ public:
+ ValidateConstIndexExpr(TLoopStack& stack)
+ : mValid(true), mLoopStack(stack) {}
+
+ // Returns true if the parsed node represents a constant index expression.
+ bool isValid() const { return mValid; }
+
+ virtual void visitSymbol(TIntermSymbol *symbol)
+ {
+ // Only constants and loop indices are allowed in a
+ // constant index expression.
+ if (mValid)
+ {
+ mValid = (symbol->getQualifier() == EvqConst) ||
+ (mLoopStack.findLoop(symbol));
+ }
+ }
+
+ private:
+ bool mValid;
+ TLoopStack& mLoopStack;
+};
+
+} // namespace anonymous
+
+ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
+ TInfoSinkBase &sink)
+ : mShaderType(shaderType),
+ mSink(sink),
+ mNumErrors(0)
+{
+}
+
+bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getLeft());
+
+ // Check indexing.
+ switch (node->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ validateIndexing(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getOperand());
+
+ return true;
+}
+
+bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
+{
+ switch (node->getOp()) {
+ case EOpFunctionCall:
+ validateFunctionCall(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
+{
+ if (!validateLoopType(node))
+ return false;
+
+ if (!validateForLoopHeader(node))
+ return false;
+
+ TIntermNode *body = node->getBody();
+ if (body != NULL)
+ {
+ mLoopStack.push(node);
+ body->traverse(this);
+ mLoopStack.pop();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ValidateLimitations::error(TSourceLoc loc,
+ const char *reason, const char *token)
+{
+ mSink.prefix(EPrefixError);
+ mSink.location(loc);
+ mSink << "'" << token << "' : " << reason << "\n";
+ ++mNumErrors;
+}
+
+bool ValidateLimitations::withinLoopBody() const
+{
+ return !mLoopStack.empty();
+}
+
+bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol)
+{
+ return mLoopStack.findLoop(symbol) != NULL;
+}
+
+bool ValidateLimitations::validateLoopType(TIntermLoop *node)
+{
+ TLoopType type = node->getType();
+ if (type == ELoopFor)
+ return true;
+
+ // Reject while and do-while loops.
+ error(node->getLine(),
+ "This type of loop is not allowed",
+ type == ELoopWhile ? "while" : "do");
+ return false;
+}
+
+bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node)
+{
+ ASSERT(node->getType() == ELoopFor);
+
+ //
+ // The for statement has the form:
+ // for ( init-declaration ; condition ; expression ) statement
+ //
+ int indexSymbolId = validateForLoopInit(node);
+ if (indexSymbolId < 0)
+ return false;
+ if (!validateForLoopCond(node, indexSymbolId))
+ return false;
+ if (!validateForLoopExpr(node, indexSymbolId))
+ return false;
+
+ return true;
+}
+
+int ValidateLimitations::validateForLoopInit(TIntermLoop *node)
+{
+ TIntermNode *init = node->getInit();
+ if (init == NULL)
+ {
+ error(node->getLine(), "Missing init declaration", "for");
+ return -1;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermAggregate *decl = init->getAsAggregate();
+ if ((decl == NULL) || (decl->getOp() != EOpDeclaration))
+ {
+ error(init->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ // To keep things simple do not allow declaration list.
+ TIntermSequence &declSeq = decl->getSequence();
+ if (declSeq.size() != 1)
+ {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ TIntermBinary *declInit = declSeq[0]->getAsBinaryNode();
+ if ((declInit == NULL) || (declInit->getOp() != EOpInitialize))
+ {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == NULL)
+ {
+ error(declInit->getLine(), "Invalid init declaration", "for");
+ return -1;
+ }
+ // The loop index has type int or float.
+ TBasicType type = symbol->getBasicType();
+ if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) {
+ error(symbol->getLine(),
+ "Invalid type for loop index", getBasicString(type));
+ return -1;
+ }
+ // The loop index is initialized with constant expression.
+ if (!isConstExpr(declInit->getRight()))
+ {
+ error(declInit->getLine(),
+ "Loop index cannot be initialized with non-constant expression",
+ symbol->getSymbol().c_str());
+ return -1;
+ }
+
+ return symbol->getId();
+}
+
+bool ValidateLimitations::validateForLoopCond(TIntermLoop *node,
+ int indexSymbolId)
+{
+ TIntermNode *cond = node->getCondition();
+ if (cond == NULL)
+ {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary *binOp = cond->getAsBinaryNode();
+ if (binOp == NULL)
+ {
+ error(node->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ // Loop index should be to the left of relational operator.
+ TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode();
+ if (symbol == NULL)
+ {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->getId() != indexSymbolId)
+ {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (binOp->getOp())
+ {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(),
+ "Invalid relational operator",
+ getOperatorString(binOp->getOp()));
+ break;
+ }
+ // Loop index must be compared with a constant.
+ if (!isConstExpr(binOp->getRight()))
+ {
+ error(binOp->getLine(),
+ "Loop index cannot be compared with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node,
+ int indexSymbolId)
+{
+ TIntermNode *expr = node->getExpression();
+ if (expr == NULL)
+ {
+ error(node->getLine(), "Missing expression", "for");
+ return false;
+ }
+
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary *unOp = expr->getAsUnaryNode();
+ TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol *symbol = NULL;
+ if (unOp != NULL)
+ {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ }
+ else if (binOp != NULL)
+ {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == NULL)
+ {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->getId() != indexSymbolId)
+ {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op)
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", getOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != NULL)
+ {
+ if (!isConstExpr(binOp->getRight()))
+ {
+ error(binOp->getLine(),
+ "Loop index cannot be modified by non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
+{
+ ASSERT(node->getOp() == EOpFunctionCall);
+
+ // If not within loop body, there is nothing to check.
+ if (!withinLoopBody())
+ return true;
+
+ // List of param indices for which loop indices are used as argument.
+ typedef std::vector<size_t> ParamIndex;
+ ParamIndex pIndex;
+ TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::size_type i = 0; i < params.size(); ++i)
+ {
+ TIntermSymbol *symbol = params[i]->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ pIndex.push_back(i);
+ }
+ // If none of the loop indices are used as arguments,
+ // there is nothing to check.
+ if (pIndex.empty())
+ return true;
+
+ bool valid = true;
+ TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
+ TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
+ ASSERT(symbol && symbol->isFunction());
+ TFunction *function = static_cast<TFunction *>(symbol);
+ for (ParamIndex::const_iterator i = pIndex.begin();
+ i != pIndex.end(); ++i)
+ {
+ const TParameter &param = function->getParam(*i);
+ TQualifier qual = param.type->getQualifier();
+ if ((qual == EvqOut) || (qual == EvqInOut))
+ {
+ error(params[*i]->getLine(),
+ "Loop index cannot be used as argument to a function out or inout parameter",
+ params[*i]->getAsSymbolNode()->getSymbol().c_str());
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+bool ValidateLimitations::validateOperation(TIntermOperator *node,
+ TIntermNode* operand)
+{
+ // Check if loop index is modified in the loop body.
+ if (!withinLoopBody() || !node->isAssignment())
+ return true;
+
+ TIntermSymbol *symbol = operand->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ symbol->getSymbol().c_str());
+ }
+ return true;
+}
+
+bool ValidateLimitations::isConstExpr(TIntermNode *node)
+{
+ ASSERT(node != NULL);
+ return node->getAsConstantUnion() != NULL;
+}
+
+bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
+{
+ ASSERT(node != NULL);
+
+ ValidateConstIndexExpr validate(mLoopStack);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitations::validateIndexing(TIntermBinary *node)
+{
+ ASSERT((node->getOp() == EOpIndexDirect) ||
+ (node->getOp() == EOpIndexIndirect));
+
+ bool valid = true;
+ TIntermTyped *index = node->getRight();
+ // The index expression must have integral type.
+ if (!index->isScalarInt()) {
+ error(index->getLine(),
+ "Index expression must have integral type",
+ index->getCompleteString().c_str());
+ valid = false;
+ }
+ // The index expession must be a constant-index-expression unless
+ // the operand is a uniform in a vertex shader.
+ TIntermTyped *operand = node->getLeft();
+ bool skip = (mShaderType == SH_VERTEX_SHADER) &&
+ (operand->getQualifier() == EvqUniform);
+ if (!skip && !isConstIndexExpr(index))
+ {
+ error(index->getLine(), "Index expression must be constant", "[]");
+ valid = false;
+ }
+ return valid;
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h
new file mode 100644
index 00000000000..f28995c640b
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/LoopInfo.h"
+
+class TInfoSinkBase;
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitations : public TIntermTraverser
+{
+ public:
+ ValidateLimitations(ShShaderType shaderType, TInfoSinkBase &sink);
+
+ int numErrors() const { return mNumErrors; }
+
+ virtual bool visitBinary(Visit, TIntermBinary *);
+ virtual bool visitUnary(Visit, TIntermUnary *);
+ virtual bool visitAggregate(Visit, TIntermAggregate *);
+ virtual bool visitLoop(Visit, TIntermLoop *);
+
+ private:
+ void error(TSourceLoc loc, const char *reason, const char *token);
+
+ bool withinLoopBody() const;
+ bool isLoopIndex(TIntermSymbol *symbol);
+ bool validateLoopType(TIntermLoop *node);
+
+ bool validateForLoopHeader(TIntermLoop *node);
+ // If valid, return the index symbol id; Otherwise, return -1.
+ int validateForLoopInit(TIntermLoop *node);
+ bool validateForLoopCond(TIntermLoop *node, int indexSymbolId);
+ bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId);
+
+ // Returns true if none of the loop indices is used as the argument to
+ // the given function out or inout parameter.
+ bool validateFunctionCall(TIntermAggregate *node);
+ bool validateOperation(TIntermOperator *node, TIntermNode *operand);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode *node);
+ bool isConstIndexExpr(TIntermNode *node);
+ bool validateIndexing(TIntermBinary *node);
+
+ ShShaderType mShaderType;
+ TInfoSinkBase &mSink;
+ int mNumErrors;
+ TLoopStack mLoopStack;
+};
+
diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp
new file mode 100644
index 00000000000..ac1c10d6b03
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateOutputs.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/ParseContext.h"
+
+ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers)
+ : mSink(sink),
+ mMaxDrawBuffers(maxDrawBuffers),
+ mNumErrors(0),
+ mHasUnspecifiedOutputLocation(false)
+{
+}
+
+void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
+{
+ TString name = symbol->getSymbol();
+ TQualifier qualifier = symbol->getQualifier();
+
+ if (mVisitedSymbols.count(name) == 1)
+ return;
+
+ mVisitedSymbols.insert(name);
+
+ if (qualifier == EvqFragmentOut)
+ {
+ const TType &type = symbol->getType();
+ const int location = type.getLayoutQualifier().location;
+
+ if (mHasUnspecifiedOutputLocation)
+ {
+ error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str());
+ }
+ else if (location == -1)
+ {
+ mHasUnspecifiedOutputLocation = true;
+ }
+ else
+ {
+ OutputMap::iterator mapEntry = mOutputMap.find(location);
+ if (mapEntry == mOutputMap.end())
+ {
+ const int elementCount = type.isArray() ? type.getArraySize() : 1;
+ if (location + elementCount > mMaxDrawBuffers)
+ {
+ error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str());
+ }
+
+ for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
+ {
+ const int offsetLocation = location + elementIndex;
+ mOutputMap[offsetLocation] = symbol;
+ }
+ }
+ else
+ {
+ std::stringstream strstr;
+ strstr << "conflicting output locations with previously defined output '"
+ << mapEntry->second->getSymbol() << "'";
+
+ error(symbol->getLine(), strstr.str().c_str(), name.c_str());
+ }
+ }
+ }
+}
+
+void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token)
+{
+ mSink.prefix(EPrefixError);
+ mSink.location(loc);
+ mSink << "'" << token << "' : " << reason << "\n";
+ mNumErrors++;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h
new file mode 100644
index 00000000000..e391ad94860
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/intermediate.h"
+
+#include <set>
+
+class TInfoSinkBase;
+
+class ValidateOutputs : public TIntermTraverser
+{
+ public:
+ ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers);
+
+ int numErrors() const { return mNumErrors; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+
+ private:
+ TInfoSinkBase& mSink;
+ int mMaxDrawBuffers;
+ int mNumErrors;
+ bool mHasUnspecifiedOutputLocation;
+
+ typedef std::map<int, TIntermSymbol*> OutputMap;
+ OutputMap mOutputMap;
+ std::set<TString> mVisitedSymbols;
+
+ void error(TSourceLoc loc, const char *reason, const char* token);
+};
diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp
new file mode 100644
index 00000000000..d0b19907f4c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp
@@ -0,0 +1,374 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/VariableInfo.h"
+
+namespace {
+
+TString arrayBrackets(int index)
+{
+ TStringStream stream;
+ stream << "[" << index << "]";
+ return stream.str();
+}
+
+// Returns the data type for an attribute, uniform, or varying.
+ShDataType getVariableDataType(const TType& type)
+{
+ switch (type.getBasicType()) {
+ case EbtFloat:
+ if (type.isMatrix()) {
+ switch (type.getCols())
+ {
+ case 2:
+ switch (type.getRows())
+ {
+ case 2: return SH_FLOAT_MAT2;
+ case 3: return SH_FLOAT_MAT2x3;
+ case 4: return SH_FLOAT_MAT2x4;
+ default: UNREACHABLE();
+ }
+ case 3:
+ switch (type.getRows())
+ {
+ case 2: return SH_FLOAT_MAT3x2;
+ case 3: return SH_FLOAT_MAT3;
+ case 4: return SH_FLOAT_MAT3x4;
+ default: UNREACHABLE();
+ }
+ case 4:
+ switch (type.getRows())
+ {
+ case 2: return SH_FLOAT_MAT4x2;
+ case 3: return SH_FLOAT_MAT4x3;
+ case 4: return SH_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+ }
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_VEC2;
+ case 3: return SH_FLOAT_VEC3;
+ case 4: return SH_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_FLOAT;
+ }
+ case EbtInt:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_INT_VEC2;
+ case 3: return SH_INT_VEC3;
+ case 4: return SH_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_INT;
+ }
+ case EbtUInt:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_UNSIGNED_INT_VEC2;
+ case 3: return SH_UNSIGNED_INT_VEC3;
+ case 4: return SH_UNSIGNED_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_UNSIGNED_INT;
+ }
+ case EbtBool:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_BOOL_VEC2;
+ case 3: return SH_BOOL_VEC3;
+ case 4: return SH_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_BOOL;
+ }
+ case EbtSampler2D: return SH_SAMPLER_2D;
+ case EbtSampler3D: return SH_SAMPLER_3D;
+ case EbtSamplerCube: return SH_SAMPLER_CUBE;
+ case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES;
+ case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB;
+ case EbtSampler2DArray: return SH_SAMPLER_2D_ARRAY;
+ case EbtISampler2D: return SH_INT_SAMPLER_2D;
+ case EbtISampler3D: return SH_INT_SAMPLER_3D;
+ case EbtISamplerCube: return SH_INT_SAMPLER_CUBE;
+ case EbtISampler2DArray: return SH_INT_SAMPLER_2D_ARRAY;
+ case EbtUSampler2D: return SH_UNSIGNED_INT_SAMPLER_2D;
+ case EbtUSampler3D: return SH_UNSIGNED_INT_SAMPLER_3D;
+ case EbtUSamplerCube: return SH_UNSIGNED_INT_SAMPLER_CUBE;
+ case EbtUSampler2DArray: return SH_UNSIGNED_INT_SAMPLER_2D_ARRAY;
+ case EbtSampler2DShadow: return SH_SAMPLER_2D_SHADOW;
+ case EbtSamplerCubeShadow: return SH_SAMPLER_CUBE_SHADOW;
+ case EbtSampler2DArrayShadow: return SH_SAMPLER_2D_ARRAY_SHADOW;
+ default: UNREACHABLE();
+ }
+ return SH_NONE;
+}
+
+void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction);
+
+// Returns info for an attribute, uniform, or varying.
+void getVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction)
+{
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
+ if (type.isArray()) {
+ for (int i = 0; i < type.getArraySize(); ++i) {
+ TString lname = name + arrayBrackets(i);
+ TString lmappedName = mappedName + arrayBrackets(i);
+ getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction);
+ }
+ } else {
+ getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction);
+ }
+ } else {
+ getBuiltInVariableInfo(type, name, mappedName, infoList);
+ }
+}
+
+void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() != EbtStruct);
+
+ TVariableInfo varInfo;
+ if (type.isArray()) {
+ varInfo.name = (name + "[0]").c_str();
+ varInfo.mappedName = (mappedName + "[0]").c_str();
+ varInfo.size = type.getArraySize();
+ varInfo.isArray = true;
+ } else {
+ varInfo.name = name.c_str();
+ varInfo.mappedName = mappedName.c_str();
+ varInfo.size = 1;
+ varInfo.isArray = false;
+ }
+ varInfo.precision = type.getPrecision();
+ varInfo.type = getVariableDataType(type);
+ infoList.push_back(varInfo);
+}
+
+void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction)
+{
+ ASSERT(type.getBasicType() == EbtStruct || type.isInterfaceBlock());
+
+ const TFieldList& fields = type.isInterfaceBlock() ?
+ type.getInterfaceBlock()->fields() :
+ type.getStruct()->fields();
+ for (size_t i = 0; i < fields.size(); ++i) {
+ const TType& fieldType = *(fields[i]->type());
+ const TString& fieldName = fields[i]->name();
+ getVariableInfo(fieldType,
+ name + "." + fieldName,
+ mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction),
+ infoList,
+ hashFunction);
+ }
+}
+
+TVariableInfo* findVariable(const TType& type,
+ const TString& name,
+ TVariableInfoList& infoList)
+{
+ // TODO(zmo): optimize this function.
+ TString myName = name;
+ if (type.isArray())
+ myName += "[0]";
+ for (size_t ii = 0; ii < infoList.size(); ++ii)
+ {
+ if (infoList[ii].name.c_str() == myName)
+ return &(infoList[ii]);
+ }
+ return NULL;
+}
+
+} // namespace anonymous
+
+TVariableInfo::TVariableInfo()
+ : type(SH_NONE),
+ size(0),
+ isArray(false),
+ precision(EbpUndefined),
+ staticUse(false)
+{
+}
+
+TVariableInfo::TVariableInfo(ShDataType type, int size)
+ : type(type),
+ size(size),
+ isArray(false),
+ precision(EbpUndefined),
+ staticUse(false)
+{
+}
+
+CollectVariables::CollectVariables(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms,
+ TVariableInfoList& varyings,
+ ShHashFunction64 hashFunction)
+ : mAttribs(attribs),
+ mUniforms(uniforms),
+ mVaryings(varyings),
+ mPointCoordAdded(false),
+ mFrontFacingAdded(false),
+ mFragCoordAdded(false),
+ mHashFunction(hashFunction)
+{
+}
+
+// We want to check whether a uniform/varying is statically used
+// because we only count the used ones in packing computing.
+// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
+// toward varying counting if they are statically used in a fragment
+// shader.
+void CollectVariables::visitSymbol(TIntermSymbol* symbol)
+{
+ ASSERT(symbol != NULL);
+ TVariableInfo* var = NULL;
+ switch (symbol->getQualifier())
+ {
+ case EvqVaryingOut:
+ case EvqInvariantVaryingOut:
+ case EvqVaryingIn:
+ case EvqInvariantVaryingIn:
+ var = findVariable(symbol->getType(), symbol->getSymbol(), mVaryings);
+ break;
+ case EvqUniform:
+ var = findVariable(symbol->getType(), symbol->getSymbol(), mUniforms);
+ break;
+ case EvqFragCoord:
+ if (!mFragCoordAdded) {
+ TVariableInfo info;
+ info.name = "gl_FragCoord";
+ info.mappedName = "gl_FragCoord";
+ info.type = SH_FLOAT_VEC4;
+ info.size = 1;
+ info.precision = EbpMedium; // Use mediump as it doesn't really matter.
+ info.staticUse = true;
+ mVaryings.push_back(info);
+ mFragCoordAdded = true;
+ }
+ return;
+ case EvqFrontFacing:
+ if (!mFrontFacingAdded) {
+ TVariableInfo info;
+ info.name = "gl_FrontFacing";
+ info.mappedName = "gl_FrontFacing";
+ info.type = SH_BOOL;
+ info.size = 1;
+ info.precision = EbpUndefined;
+ info.staticUse = true;
+ mVaryings.push_back(info);
+ mFrontFacingAdded = true;
+ }
+ return;
+ case EvqPointCoord:
+ if (!mPointCoordAdded) {
+ TVariableInfo info;
+ info.name = "gl_PointCoord";
+ info.mappedName = "gl_PointCoord";
+ info.type = SH_FLOAT_VEC2;
+ info.size = 1;
+ info.precision = EbpMedium; // Use mediump as it doesn't really matter.
+ info.staticUse = true;
+ mVaryings.push_back(info);
+ mPointCoordAdded = true;
+ }
+ return;
+ default:
+ break;
+ }
+ if (var)
+ var->staticUse = true;
+}
+
+bool CollectVariables::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp())
+ {
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if (qualifier == EvqAttribute || qualifier == EvqVertexIn || qualifier == EvqUniform ||
+ qualifier == EvqVaryingIn || qualifier == EvqVaryingOut ||
+ qualifier == EvqInvariantVaryingIn || qualifier == EvqInvariantVaryingOut)
+ {
+ TVariableInfoList *infoList = NULL;
+
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ infoList = &mAttribs;
+ break;
+ case EvqUniform:
+ infoList = &mUniforms;
+ break;
+ default:
+ infoList = &mVaryings;
+ break;
+ }
+
+ for (TIntermSequence::const_iterator i = sequence.begin();
+ i != sequence.end(); ++i)
+ {
+ const TIntermSymbol* variable = (*i)->getAsSymbolNode();
+ // The only case in which the sequence will not contain a
+ // TIntermSymbol node is initialization. It will contain a
+ // TInterBinary node in that case. Since attributes, uniforms,
+ // and varyings cannot be initialized in a shader, we must have
+ // only TIntermSymbol nodes in the sequence.
+ ASSERT(variable != NULL);
+ TString processedSymbol;
+ if (mHashFunction == NULL)
+ processedSymbol = variable->getSymbol();
+ else
+ processedSymbol = TIntermTraverser::hash(variable->getSymbol(), mHashFunction);
+ getVariableInfo(variable->getType(),
+ variable->getSymbol(),
+ processedSymbol,
+ *infoList,
+ mHashFunction);
+ visitChildren = false;
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return visitChildren;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.h b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h
new file mode 100644
index 00000000000..fc9e15301bc
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VARIABLE_INFO_H_
+#define COMPILER_VARIABLE_INFO_H_
+
+#include "compiler/translator/intermediate.h"
+
+// Provides information about a variable.
+// It is currently being used to store info about active attribs and uniforms.
+struct TVariableInfo {
+ TVariableInfo(ShDataType type, int size);
+ TVariableInfo();
+
+ TPersistString name;
+ TPersistString mappedName;
+ ShDataType type;
+ int size;
+ bool isArray;
+ TPrecision precision;
+ bool staticUse;
+};
+typedef std::vector<TVariableInfo> TVariableInfoList;
+
+// Traverses intermediate tree to collect all attributes, uniforms, varyings.
+class CollectVariables : public TIntermTraverser {
+public:
+ CollectVariables(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms,
+ TVariableInfoList& varyings,
+ ShHashFunction64 hashFunction);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+
+private:
+ TVariableInfoList& mAttribs;
+ TVariableInfoList& mUniforms;
+ TVariableInfoList& mVaryings;
+
+ bool mPointCoordAdded;
+ bool mFrontFacingAdded;
+ bool mFragCoordAdded;
+
+ ShHashFunction64 mHashFunction;
+};
+
+#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp
new file mode 100644
index 00000000000..6390e303941
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp
@@ -0,0 +1,323 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "compiler/translator/VariablePacker.h"
+
+#include <algorithm>
+#include "compiler/translator/ShHandle.h"
+
+namespace {
+int GetSortOrder(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ case SH_FLOAT_MAT2x4:
+ case SH_FLOAT_MAT3x4:
+ case SH_FLOAT_MAT4x2:
+ case SH_FLOAT_MAT4x3:
+ return 0;
+ case SH_FLOAT_MAT2:
+ return 1;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 2;
+ case SH_FLOAT_MAT3:
+ case SH_FLOAT_MAT2x3:
+ case SH_FLOAT_MAT3x2:
+ return 3;
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 4;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 5;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 6;
+ default:
+ ASSERT(false);
+ return 7;
+ }
+}
+} // namespace
+
+int VariablePacker::GetNumComponentsPerRow(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ case SH_FLOAT_MAT2:
+ case SH_FLOAT_MAT2x4:
+ case SH_FLOAT_MAT3x4:
+ case SH_FLOAT_MAT4x2:
+ case SH_FLOAT_MAT4x3:
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 4;
+ case SH_FLOAT_MAT3:
+ case SH_FLOAT_MAT2x3:
+ case SH_FLOAT_MAT3x2:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 3;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 2;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 5;
+ }
+}
+
+int VariablePacker::GetNumRows(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ case SH_FLOAT_MAT2x4:
+ case SH_FLOAT_MAT3x4:
+ case SH_FLOAT_MAT4x3:
+ case SH_FLOAT_MAT4x2:
+ return 4;
+ case SH_FLOAT_MAT3:
+ case SH_FLOAT_MAT2x3:
+ case SH_FLOAT_MAT3x2:
+ return 3;
+ case SH_FLOAT_MAT2:
+ return 2;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 100000;
+ }
+}
+
+struct TVariableInfoComparer {
+ bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const
+ {
+ int lhsSortOrder = GetSortOrder(lhs.type);
+ int rhsSortOrder = GetSortOrder(rhs.type);
+ if (lhsSortOrder != rhsSortOrder) {
+ return lhsSortOrder < rhsSortOrder;
+ }
+ // Sort by largest first.
+ return lhs.size > rhs.size;
+ }
+};
+
+unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
+{
+ return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
+ kColumnMask) >> column;
+}
+
+void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
+{
+ unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
+ for (int r = 0; r < numRows; ++r) {
+ int row = topRow + r;
+ ASSERT((rows_[row] & columnFlags) == 0);
+ rows_[row] |= columnFlags;
+ }
+}
+
+bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
+{
+ ASSERT(destRow);
+
+ for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
+ ++topNonFullRow_) {
+ }
+
+ for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
+ --bottomNonFullRow_) {
+ }
+
+ if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
+ return false;
+ }
+
+ unsigned columnFlags = makeColumnFlags(column, 1);
+ int topGoodRow = 0;
+ int smallestGoodTop = -1;
+ int smallestGoodSize = maxRows_ + 1;
+ int bottomRow = bottomNonFullRow_ + 1;
+ bool found = false;
+ for (int row = topNonFullRow_; row <= bottomRow; ++row) {
+ bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
+ if (rowEmpty) {
+ if (!found) {
+ topGoodRow = row;
+ found = true;
+ }
+ } else {
+ if (found) {
+ int size = row - topGoodRow;
+ if (size >= numRows && size < smallestGoodSize) {
+ smallestGoodSize = size;
+ smallestGoodTop = topGoodRow;
+ }
+ }
+ found = false;
+ }
+ }
+ if (smallestGoodTop < 0) {
+ return false;
+ }
+
+ *destRow = smallestGoodTop;
+ if (destSize) {
+ *destSize = smallestGoodSize;
+ }
+ return true;
+}
+
+bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables)
+{
+ ASSERT(maxVectors > 0);
+ maxRows_ = maxVectors;
+ topNonFullRow_ = 0;
+ bottomNonFullRow_ = maxRows_ - 1;
+ TVariableInfoList variables(in_variables);
+
+ // Check whether each variable fits in the available vectors.
+ for (size_t i = 0; i < variables.size(); i++) {
+ const TVariableInfo& variable = variables[i];
+ if (variable.size > maxVectors / GetNumRows(variable.type)) {
+ return false;
+ }
+ }
+
+ // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
+ // order by type, then by size of array, largest first.
+ std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
+ rows_.clear();
+ rows_.resize(maxVectors, 0);
+
+ // Packs the 4 column variables.
+ size_t ii = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 4) {
+ break;
+ }
+ topNonFullRow_ += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ > maxRows_) {
+ return false;
+ }
+
+ // Packs the 3 column variables.
+ int num3ColumnRows = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 3) {
+ break;
+ }
+ num3ColumnRows += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ + num3ColumnRows > maxRows_) {
+ return false;
+ }
+
+ fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
+
+ // Packs the 2 column variables.
+ int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
+ int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
+ int rowsAvailableInColumns01 = twoColumnRowsAvailable;
+ int rowsAvailableInColumns23 = twoColumnRowsAvailable;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 2) {
+ break;
+ }
+ int numRows = GetNumRows(variable.type) * variable.size;
+ if (numRows <= rowsAvailableInColumns01) {
+ rowsAvailableInColumns01 -= numRows;
+ } else if (numRows <= rowsAvailableInColumns23) {
+ rowsAvailableInColumns23 -= numRows;
+ } else {
+ return false;
+ }
+ }
+
+ int numRowsUsedInColumns01 =
+ twoColumnRowsAvailable - rowsAvailableInColumns01;
+ int numRowsUsedInColumns23 =
+ twoColumnRowsAvailable - rowsAvailableInColumns23;
+ fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
+ fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
+ 2, 2);
+
+ // Packs the 1 column variables.
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ ASSERT(1 == GetNumComponentsPerRow(variable.type));
+ int numRows = GetNumRows(variable.type) * variable.size;
+ int smallestColumn = -1;
+ int smallestSize = maxRows_ + 1;
+ int topRow = -1;
+ for (int column = 0; column < kNumColumns; ++column) {
+ int row = 0;
+ int size = 0;
+ if (searchColumn(column, numRows, &row, &size)) {
+ if (size < smallestSize) {
+ smallestSize = size;
+ smallestColumn = column;
+ topRow = row;
+ }
+ }
+ }
+
+ if (smallestColumn < 0) {
+ return false;
+ }
+
+ fillColumns(topRow, numRows, smallestColumn, 1);
+ }
+
+ ASSERT(variables.size() == ii);
+
+ return true;
+}
+
+
+
diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.h b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h
new file mode 100644
index 00000000000..fd6090827cd
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _VARIABLEPACKER_INCLUDED_
+#define _VARIABLEPACKER_INCLUDED_
+
+#include <vector>
+#include "compiler/translator/ShHandle.h"
+
+class VariablePacker {
+ public:
+ // Returns true if the passed in variables pack in maxVectors following
+ // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+ bool CheckVariablesWithinPackingLimits(
+ int maxVectors,
+ const TVariableInfoList& in_variables);
+
+ // Gets how many components in a row a data type takes.
+ static int GetNumComponentsPerRow(ShDataType type);
+
+ // Gets how many rows a data type takes.
+ static int GetNumRows(ShDataType type);
+
+ private:
+ static const int kNumColumns = 4;
+ static const unsigned kColumnMask = (1 << kNumColumns) - 1;
+
+ unsigned makeColumnFlags(int column, int numComponentsPerRow);
+ void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
+ bool searchColumn(int column, int numRows, int* destRow, int* destSize);
+
+ int topNonFullRow_;
+ int bottomNonFullRow_;
+ int maxRows_;
+ std::vector<unsigned> rows_;
+};
+
+#endif // _VARIABLEPACKER_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp
new file mode 100644
index 00000000000..dd11f99eb89
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp
@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/VersionGLSL.h"
+
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+
+// We need to scan for the following:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+// but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+// but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+// (These constructors were reserved in GLSL version 1.10.)
+// 4. Arrays as "out" function parameters.
+// GLSL spec section 6.1.1: "When calling a function, expressions that do
+// not evaluate to l-values cannot be passed to parameters declared as
+// out or inout."
+// GLSL 1.1 section 5.8: "Other binary or unary expressions,
+// non-dereferenced arrays, function names, swizzles with repeated fields,
+// and constants cannot be l-values."
+// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
+// are built-in types, entire structures or arrays... are all l-values."
+//
+// TODO(alokp): The following two cases of invariant decalaration get lost
+// during parsing - they do not get carried over to the intermediate tree.
+// Handle these cases:
+// 1. When a pragma is used to force all output variables to be invariant:
+// - #pragma STDGL invariant(all)
+// 2. When a previously decalared or built-in variable is marked invariant:
+// - invariant gl_Position;
+// - varying vec3 color; invariant color;
+//
+TVersionGLSL::TVersionGLSL(ShShaderType type)
+ : mShaderType(type),
+ mVersion(GLSL_VERSION_110)
+{
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol* node)
+{
+ if (node->getSymbol() == "gl_PointCoord")
+ updateVersion(GLSL_VERSION_120);
+}
+
+void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool TVersionGLSL::visitBinary(Visit, TIntermBinary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitUnary(Visit, TIntermUnary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp()) {
+ case EOpSequence:
+ // We need to visit sequence children to get to global or inner scope.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if ((qualifier == EvqInvariantVaryingIn) ||
+ (qualifier == EvqInvariantVaryingOut)) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ break;
+ }
+ case EOpParameters: {
+ const TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::const_iterator iter = params.begin();
+ iter != params.end(); ++iter)
+ {
+ const TIntermTyped* param = (*iter)->getAsTyped();
+ if (param->isArray())
+ {
+ TQualifier qualifier = param->getQualifier();
+ if ((qualifier == EvqOut) || (qualifier == EvqInOut))
+ {
+ updateVersion(GLSL_VERSION_120);
+ break;
+ }
+ }
+ }
+ // Fully processed. No need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4: {
+ const TIntermSequence& sequence = node->getSequence();
+ if (sequence.size() == 1) {
+ TIntermTyped* typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix()) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool TVersionGLSL::visitLoop(Visit, TIntermLoop*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+void TVersionGLSL::updateVersion(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h
new file mode 100644
index 00000000000..8a401c4e92b
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VERSIONGLSL_H_
+#define COMPILER_VERSIONGLSL_H_
+
+#include "compiler/translator/intermediate.h"
+
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+// - #version and #extension to declare version and extensions.
+// - built-in functions refract, exp, and log.
+// - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+// - many changes to reduce differences when compared to the ES specification.
+// - invariant keyword and its support.
+// - c++ style name hiding rules.
+// - built-in variable gl_PointCoord for fragment shaders.
+// - matrix constructors taking matrix as argument.
+// - array as "out" function parameters
+//
+// TODO: ES3 equivalent versions of GLSL
+class TVersionGLSL : public TIntermTraverser {
+public:
+ TVersionGLSL(ShShaderType type);
+
+ // Returns 120 if the following is used the shader:
+ // - "invariant",
+ // - "gl_PointCoord",
+ // - matrix/matrix constructors
+ // - array "out" parameters
+ // Else 110 is returned.
+ int getVersion() { return mVersion; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+protected:
+ void updateVersion(int version);
+
+private:
+ ShShaderType mShaderType;
+ int mVersion;
+};
+
+#endif // COMPILER_VERSIONGLSL_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp b/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp
new file mode 100644
index 00000000000..10cbe43b8d5
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "compiler/translator/compilerdebug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/translator/InitializeParseContext.h"
+#include "compiler/translator/ParseContext.h"
+
+#ifdef TRACE_ENABLED
+static const int kTraceBufferLen = 1024;
+
+extern "C" {
+void Trace(const char *format, ...) {
+ if (!format) return;
+
+ TParseContext* parseContext = GetGlobalParseContext();
+ if (parseContext) {
+ char buf[kTraceBufferLen];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, kTraceBufferLen, format, args);
+ va_end(args);
+
+ parseContext->trace(buf);
+ }
+}
+} // extern "C"
+#endif // TRACE_ENABLED
+
diff --git a/chromium/third_party/angle/src/compiler/translator/compilerdebug.h b/chromium/third_party/angle/src/compiler/translator/compilerdebug.h
new file mode 100644
index 00000000000..7a371516af0
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/compilerdebug.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMPILER_DEBUG_H_
+#define COMPILER_DEBUG_H_
+
+#include <assert.h>
+
+#ifdef _DEBUG
+#define TRACE_ENABLED // define to enable debug message tracing
+#endif // _DEBUG
+
+// Outputs text to the debug log
+#ifdef TRACE_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+void Trace(const char* format, ...);
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#else // TRACE_ENABLED
+
+#define Trace(...) ((void)0)
+
+#endif // TRACE_ENABLED
+
+// A macro asserting a condition and outputting failures to the debug log
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+} while(0)
+
+#define UNIMPLEMENTED() do { \
+ Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#define UNREACHABLE() do { \
+ Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#endif // COMPILER_DEBUG_H_
+
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp
new file mode 100644
index 00000000000..19ddf5c4392
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#pragma warning(disable: 4718)
+
+#include "compiler/translator/depgraph/DependencyGraph.h"
+#include "compiler/translator/depgraph/DependencyGraphBuilder.h"
+
+TDependencyGraph::TDependencyGraph(TIntermNode* intermNode)
+{
+ TDependencyGraphBuilder::build(intermNode, this);
+}
+
+TDependencyGraph::~TDependencyGraph()
+{
+ for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter)
+ {
+ TGraphNode* node = *iter;
+ delete node;
+ }
+}
+
+TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall,
+ int argumentNumber)
+{
+ TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber);
+ mAllNodes.push_back(argument);
+ return argument;
+}
+
+TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall);
+ mAllNodes.push_back(functionCall);
+ if (functionCall->getIntermFunctionCall()->isUserDefined())
+ mUserDefinedFunctionCalls.push_back(functionCall);
+ return functionCall;
+}
+
+TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol)
+{
+ TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId());
+
+ TGraphSymbol* symbol = NULL;
+
+ if (iter != mSymbolIdMap.end()) {
+ TSymbolIdPair pair = *iter;
+ symbol = pair.second;
+ } else {
+ symbol = new TGraphSymbol(intermSymbol);
+ mAllNodes.push_back(symbol);
+
+ TSymbolIdPair pair(intermSymbol->getId(), symbol);
+ mSymbolIdMap.insert(pair);
+
+ // We save all sampler symbols in a collection, so we can start graph traversals from them quickly.
+ if (IsSampler(intermSymbol->getBasicType()))
+ mSamplerSymbols.push_back(symbol);
+ }
+
+ return symbol;
+}
+
+TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection)
+{
+ TGraphSelection* selection = new TGraphSelection(intermSelection);
+ mAllNodes.push_back(selection);
+ return selection;
+}
+
+TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop)
+{
+ TGraphLoop* loop = new TGraphLoop(intermLoop);
+ mAllNodes.push_back(loop);
+ return loop;
+}
+
+TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp);
+ mAllNodes.push_back(logicalOp);
+ return logicalOp;
+}
+
+const char* TGraphLogicalOp::getOpString() const
+{
+ const char* opString = NULL;
+ switch (getIntermLogicalOp()->getOp()) {
+ case EOpLogicalAnd: opString = "and"; break;
+ case EOpLogicalOr: opString = "or"; break;
+ default: opString = "unknown"; break;
+ }
+ return opString;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h
new file mode 100644
index 00000000000..5ea1cbb837d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h
@@ -0,0 +1,212 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+
+#include "compiler/translator/intermediate.h"
+
+#include <set>
+#include <stack>
+
+class TGraphNode;
+class TGraphParentNode;
+class TGraphArgument;
+class TGraphFunctionCall;
+class TGraphSymbol;
+class TGraphSelection;
+class TGraphLoop;
+class TGraphLogicalOp;
+class TDependencyGraphTraverser;
+class TDependencyGraphOutput;
+
+typedef std::set<TGraphNode*> TGraphNodeSet;
+typedef std::vector<TGraphNode*> TGraphNodeVector;
+typedef std::vector<TGraphSymbol*> TGraphSymbolVector;
+typedef std::vector<TGraphFunctionCall*> TFunctionCallVector;
+
+//
+// Base class for all dependency graph nodes.
+//
+class TGraphNode {
+public:
+ TGraphNode(TIntermNode* node) : intermNode(node) {}
+ virtual ~TGraphNode() {}
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+protected:
+ TIntermNode* intermNode;
+};
+
+//
+// Base class for dependency graph nodes that may have children.
+//
+class TGraphParentNode : public TGraphNode {
+public:
+ TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
+ virtual ~TGraphParentNode() {}
+ void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ TGraphNodeSet mDependentNodes;
+};
+
+//
+// Handle function call arguments.
+//
+class TGraphArgument : public TGraphParentNode {
+public:
+ TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
+ : TGraphParentNode(intermFunctionCall)
+ , mArgumentNumber(argumentNumber) {}
+ virtual ~TGraphArgument() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ int getArgumentNumber() const { return mArgumentNumber; }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ int mArgumentNumber;
+};
+
+//
+// Handle function calls.
+//
+class TGraphFunctionCall : public TGraphParentNode {
+public:
+ TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
+ : TGraphParentNode(intermFunctionCall) {}
+ virtual ~TGraphFunctionCall() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle symbols.
+//
+class TGraphSymbol : public TGraphParentNode {
+public:
+ TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
+ virtual ~TGraphSymbol() {}
+ const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle if statements and ternary operators.
+//
+class TGraphSelection : public TGraphNode {
+public:
+ TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
+ virtual ~TGraphSelection() {}
+ const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+class TGraphLoop : public TGraphNode {
+public:
+ TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
+ virtual ~TGraphLoop() {}
+ const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle logical and, or.
+//
+class TGraphLogicalOp : public TGraphNode {
+public:
+ TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
+ virtual ~TGraphLogicalOp() {}
+ const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
+ const char* getOpString() const;
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// A dependency graph of symbols, function calls, conditions etc.
+//
+// This class provides an interface to the entry points of the dependency graph.
+//
+// Dependency graph nodes should be created by using one of the provided "create..." methods.
+// This class (and nobody else) manages the memory of the created nodes.
+// Nodes may not be removed after being added, so all created nodes will exist while the
+// TDependencyGraph instance exists.
+//
+class TDependencyGraph {
+public:
+ TDependencyGraph(TIntermNode* intermNode);
+ ~TDependencyGraph();
+ TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); }
+ TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); }
+
+ TGraphSymbolVector::const_iterator beginSamplerSymbols() const
+ {
+ return mSamplerSymbols.begin();
+ }
+
+ TGraphSymbolVector::const_iterator endSamplerSymbols() const
+ {
+ return mSamplerSymbols.end();
+ }
+
+ TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.begin();
+ }
+
+ TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.end();
+ }
+
+ TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
+ TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall);
+ TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol);
+ TGraphSelection* createSelection(TIntermSelection* intermSelection);
+ TGraphLoop* createLoop(TIntermLoop* intermLoop);
+ TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp);
+private:
+ typedef TMap<int, TGraphSymbol*> TSymbolIdMap;
+ typedef std::pair<int, TGraphSymbol*> TSymbolIdPair;
+
+ TGraphNodeVector mAllNodes;
+ TGraphSymbolVector mSamplerSymbols;
+ TFunctionCallVector mUserDefinedFunctionCalls;
+ TSymbolIdMap mSymbolIdMap;
+};
+
+//
+// For traversing the dependency graph. Users should derive from this,
+// put their traversal specific data in it, and then pass it to a
+// traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+//
+class TDependencyGraphTraverser {
+public:
+ TDependencyGraphTraverser() : mDepth(0) {}
+
+ virtual void visitSymbol(TGraphSymbol* symbol) {};
+ virtual void visitArgument(TGraphArgument* selection) {};
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {};
+ virtual void visitSelection(TGraphSelection* selection) {};
+ virtual void visitLoop(TGraphLoop* loop) {};
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {};
+
+ int getDepth() const { return mDepth; }
+ void incrementDepth() { ++mDepth; }
+ void decrementDepth() { --mDepth; }
+
+ void clearVisited() { mVisited.clear(); }
+ void markVisited(TGraphNode* node) { mVisited.insert(node); }
+ bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); }
+private:
+ int mDepth;
+ TGraphNodeSet mVisited;
+};
+
+#endif
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp
new file mode 100644
index 00000000000..d5f2cba5fc0
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp
@@ -0,0 +1,227 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/depgraph/DependencyGraphBuilder.h"
+
+void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph)
+{
+ TDependencyGraphBuilder builder(graph);
+ builder.build(node);
+}
+
+bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate)
+{
+ switch (intermAggregate->getOp()) {
+ case EOpFunction: visitFunctionDefinition(intermAggregate); break;
+ case EOpFunctionCall: visitFunctionCall(intermAggregate); break;
+ default: visitAggregateChildren(intermAggregate); break;
+ }
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate)
+{
+ // Currently, we do not support user defined functions.
+ if (intermAggregate->getName() != "main(")
+ return;
+
+ visitAggregateChildren(intermAggregate);
+}
+
+// Takes an expression like "f(x)" and creates a dependency graph like
+// "x -> argument 0 -> function call".
+void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall);
+
+ // Run through the function call arguments.
+ int argumentNumber = 0;
+ TIntermSequence& intermArguments = intermFunctionCall->getSequence();
+ for (TIntermSequence::const_iterator iter = intermArguments.begin();
+ iter != intermArguments.end();
+ ++iter, ++argumentNumber)
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ TIntermNode* intermArgument = *iter;
+ intermArgument->traverse(this);
+
+ if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) {
+ TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber);
+ connectMultipleNodesToSingleNode(argumentNodes, argument);
+ argument->addDependentNode(functionCall);
+ }
+ }
+
+ // Push the leftmost symbol of this function call into the current set of dependent symbols to
+ // represent the result of this function call.
+ // Thus, an expression like "y = f(x)" will yield a dependency graph like
+ // "x -> argument 0 -> function call -> y".
+ // This line essentially passes the function call node back up to an earlier visitAssignment
+ // call, which will create the connection "function call -> y".
+ mNodeSets.insertIntoTopSet(functionCall);
+}
+
+void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate)
+{
+ TIntermSequence& sequence = intermAggregate->getSequence();
+ for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
+ {
+ TIntermNode* intermChild = *iter;
+ intermChild->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
+{
+ // Push this symbol into the set of dependent symbols for the current assignment or condition
+ // that we are traversing.
+ TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol);
+ mNodeSets.insertIntoTopSet(symbol);
+
+ // If this symbol is the current leftmost symbol under an assignment, replace the previous
+ // leftmost symbol with this symbol.
+ if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) {
+ mLeftmostSymbols.pop();
+ mLeftmostSymbols.push(symbol);
+ }
+}
+
+bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
+{
+ TOperator op = intermBinary->getOp();
+ if (op == EOpInitialize || intermBinary->isAssignment())
+ visitAssignment(intermBinary);
+ else if (op == EOpLogicalAnd || op == EOpLogicalOr)
+ visitLogicalOp(intermBinary);
+ else
+ visitBinaryChildren(intermBinary);
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment)
+{
+ TIntermTyped* intermLeft = intermAssignment->getLeft();
+ if (!intermLeft)
+ return;
+
+ TGraphSymbol* leftmostSymbol = NULL;
+
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree);
+ intermLeft->traverse(this);
+ leftmostSymbol = mLeftmostSymbols.top();
+
+ // After traversing the left subtree of this assignment, we should have found a real
+ // leftmost symbol, and the leftmost symbol should not be a placeholder.
+ ASSERT(leftmostSymbol != &mLeftSubtree);
+ ASSERT(leftmostSymbol != &mRightSubtree);
+ }
+
+ if (TIntermTyped* intermRight = intermAssignment->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+
+ if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet())
+ connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
+ }
+
+ // Push the leftmost symbol of this assignment into the current set of dependent symbols to
+ // represent the result of this assignment.
+ // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a".
+ // This line essentially passes the leftmost symbol of the nested assignment ("b" in this
+ // example) back up to the earlier visitAssignment call for the outer assignment, which will
+ // create the connection "b -> a".
+ mNodeSets.insertIntoTopSet(leftmostSymbol);
+}
+
+void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) {
+ TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
+
+ intermLeft->traverse(this);
+ if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) {
+ TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp);
+ connectMultipleNodesToSingleNode(leftNodes, logicalOp);
+ }
+ }
+
+ if (TIntermTyped* intermRight = intermLogicalOp->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary)
+{
+ if (TIntermTyped* intermLeft = intermBinary->getLeft())
+ intermLeft->traverse(this);
+
+ if (TIntermTyped* intermRight = intermBinary->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection)
+{
+ if (TIntermNode* intermCondition = intermSelection->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphSelection* selection = mGraph->createSelection(intermSelection);
+ connectMultipleNodesToSingleNode(conditionNodes, selection);
+ }
+ }
+
+ if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock())
+ intermTrueBlock->traverse(this);
+
+ if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock())
+ intermFalseBlock->traverse(this);
+
+ return false;
+}
+
+bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop)
+{
+ if (TIntermTyped* intermCondition = intermLoop->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphLoop* loop = mGraph->createLoop(intermLoop);
+ connectMultipleNodesToSingleNode(conditionNodes, loop);
+ }
+ }
+
+ if (TIntermNode* intermBody = intermLoop->getBody())
+ intermBody->traverse(this);
+
+ if (TIntermTyped* intermExpression = intermLoop->getExpression())
+ intermExpression->traverse(this);
+
+ return false;
+}
+
+
+void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes,
+ TGraphNode* node) const
+{
+ for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter)
+ {
+ TGraphParentNode* currentNode = *iter;
+ currentNode->addDependentNode(node);
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h
new file mode 100644
index 00000000000..3e928fb77eb
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h
@@ -0,0 +1,181 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+
+#include "compiler/translator/depgraph/DependencyGraph.h"
+
+//
+// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a
+// intermediate tree.
+//
+class TDependencyGraphBuilder : public TIntermTraverser {
+public:
+ static void build(TIntermNode* node, TDependencyGraph* graph);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitBinary(Visit visit, TIntermBinary*);
+ virtual bool visitSelection(Visit visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit visit, TIntermLoop*);
+
+private:
+ typedef std::stack<TGraphSymbol*> TSymbolStack;
+ typedef std::set<TGraphParentNode*> TParentNodeSet;
+
+ //
+ // For collecting the dependent nodes of assignments, conditions, etc.
+ // while traversing the intermediate tree.
+ //
+ // This data structure is stack of sets. Each set contains dependency graph parent nodes.
+ //
+ class TNodeSetStack {
+ public:
+ TNodeSetStack() {};
+ ~TNodeSetStack() { clear(); }
+
+ // This should only be called after a pushSet.
+ // Returns NULL if the top set is empty.
+ TParentNodeSet* getTopSet() const
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* topSet = nodeSets.top();
+ return !topSet->empty() ? topSet : NULL;
+ }
+
+ void pushSet() { nodeSets.push(new TParentNodeSet()); }
+ void popSet()
+ {
+ ASSERT(!nodeSets.empty());
+ delete nodeSets.top();
+ nodeSets.pop();
+ }
+
+ // Pops the top set and adds its contents to the new top set.
+ // This should only be called after a pushSet.
+ // If there is no set below the top set, the top set is just deleted.
+ void popSetIntoNext()
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* oldTopSet = nodeSets.top();
+ nodeSets.pop();
+
+ if (!nodeSets.empty()) {
+ TParentNodeSet* newTopSet = nodeSets.top();
+ newTopSet->insert(oldTopSet->begin(), oldTopSet->end());
+ }
+
+ delete oldTopSet;
+ }
+
+ // Does nothing if there is no top set.
+ // This can be called when there is no top set if we are visiting
+ // symbols that are not under an assignment or condition.
+ // We don't need to track those symbols.
+ void insertIntoTopSet(TGraphParentNode* node)
+ {
+ if (nodeSets.empty())
+ return;
+
+ nodeSets.top()->insert(node);
+ }
+
+ void clear()
+ {
+ while (!nodeSets.empty())
+ popSet();
+ }
+
+ private:
+ typedef std::stack<TParentNodeSet*> TParentNodeSetStack;
+
+ TParentNodeSetStack nodeSets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the node set.
+ //
+ class TNodeSetMaintainer {
+ public:
+ TNodeSetMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetMaintainer() { sets.popSet(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the top node set and adds its contents to
+ // the new top node set.
+ //
+ class TNodeSetPropagatingMaintainer {
+ public:
+ TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class keeps track of the leftmost symbol while we're exploring an
+ // assignment.
+ // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree,
+ // and kRightSubtree under a right subtree.
+ // When it goes out of scope, it will pop the leftmost symbol at the top of the scope.
+ // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol.
+ // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost
+ // symbol.
+ //
+ class TLeftmostSymbolMaintainer {
+ public:
+ TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree)
+ : leftmostSymbols(factory->mLeftmostSymbols)
+ {
+ needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree;
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.push(&subtree);
+ }
+
+ ~TLeftmostSymbolMaintainer()
+ {
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.pop();
+ }
+
+ protected:
+ TSymbolStack& leftmostSymbols;
+ bool needsPlaceholderSymbol;
+ };
+
+ TDependencyGraphBuilder(TDependencyGraph* graph)
+ : TIntermTraverser(true, false, false)
+ , mLeftSubtree(NULL)
+ , mRightSubtree(NULL)
+ , mGraph(graph) {}
+ void build(TIntermNode* intermNode) { intermNode->traverse(this); }
+
+ void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const;
+
+ void visitAssignment(TIntermBinary*);
+ void visitLogicalOp(TIntermBinary*);
+ void visitBinaryChildren(TIntermBinary*);
+ void visitFunctionDefinition(TIntermAggregate*);
+ void visitFunctionCall(TIntermAggregate* intermFunctionCall);
+ void visitAggregateChildren(TIntermAggregate*);
+
+ TGraphSymbol mLeftSubtree;
+ TGraphSymbol mRightSubtree;
+
+ TDependencyGraph* mGraph;
+ TNodeSetStack mNodeSets;
+ TSymbolStack mLeftmostSymbols;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp
new file mode 100644
index 00000000000..e226333545f
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/depgraph/DependencyGraphOutput.h"
+
+void TDependencyGraphOutput::outputIndentation()
+{
+ for (int i = 0; i < getDepth(); ++i)
+ mSink << " ";
+}
+
+void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter)
+{
+ outputIndentation();
+ mSink << "argument " << parameter->getArgumentNumber() << " of call to "
+ << parameter->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall)
+{
+ outputIndentation();
+ mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol)
+{
+ outputIndentation();
+ mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: "
+ << symbol->getIntermSymbol()->getId() << ")\n";
+}
+
+void TDependencyGraphOutput::visitSelection(TGraphSelection* selection)
+{
+ outputIndentation();
+ mSink << "selection\n";
+}
+
+void TDependencyGraphOutput::visitLoop(TGraphLoop* loop)
+{
+ outputIndentation();
+ mSink << "loop condition\n";
+}
+
+void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ outputIndentation();
+ mSink << "logical " << logicalOp->getOpString() << "\n";
+}
+
+void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
+{
+ mSink << "\n";
+
+ for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter)
+ {
+ TGraphNode* symbol = *iter;
+ mSink << "--- Dependency graph spanning tree ---\n";
+ clearVisited();
+ symbol->traverse(this);
+ mSink << "\n";
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h
new file mode 100644
index 00000000000..c3a4112278f
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+
+#include "compiler/translator/depgraph/DependencyGraph.h"
+#include "compiler/translator/InfoSink.h"
+
+class TDependencyGraphOutput : public TDependencyGraphTraverser {
+public:
+ TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
+ virtual void visitSymbol(TGraphSymbol* symbol);
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+ void outputAllSpanningTrees(TDependencyGraph& graph);
+private:
+ void outputIndentation();
+
+ TInfoSinkBase& mSink;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp
new file mode 100644
index 00000000000..197fde97e26
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/depgraph/DependencyGraph.h"
+
+// These methods do a breadth-first traversal through the graph and mark visited nodes.
+
+void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->markVisited(this);
+}
+
+void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ TGraphNode::traverse(graphTraverser);
+
+ graphTraverser->incrementDepth();
+
+ // Visit the parent node's children.
+ for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin();
+ iter != mDependentNodes.end();
+ ++iter)
+ {
+ TGraphNode* node = *iter;
+ if (!graphTraverser->isVisited(node))
+ node->traverse(graphTraverser);
+ }
+
+ graphTraverser->decrementDepth();
+}
+
+void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitArgument(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitFunctionCall(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSymbol(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSelection(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLoop(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLogicalOp(this);
+ TGraphNode::traverse(graphTraverser);
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/generate_parser.sh b/chromium/third_party/angle/src/compiler/translator/generate_parser.sh
new file mode 100644
index 00000000000..e4d88b2e84c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/generate_parser.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates GLSL ES parser - glslang_lex.cpp, glslang_tab.h, and glslang_tab.cpp
+
+run_flex()
+{
+input_file=$script_dir/$1.l
+output_source=$script_dir/$1_lex.cpp
+flex --noline --nounistd --outfile=$output_source $input_file
+}
+
+run_bison()
+{
+input_file=$script_dir/$1.y
+output_header=$script_dir/$1_tab.h
+output_source=$script_dir/$1_tab.cpp
+bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file
+}
+
+script_dir=$(dirname $0)
+
+# Generate Parser
+run_flex glslang
+run_bison glslang
+patch --silent --forward < 64bit-lexer-safety.patch
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.h b/chromium/third_party/angle/src/compiler/translator/glslang.h
new file mode 100644
index 00000000000..f221199093c
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+struct TParseContext;
+extern int glslang_initialize(TParseContext* context);
+extern int glslang_finalize(TParseContext* context);
+
+extern int glslang_scan(size_t count,
+ const char* const string[],
+ const int length[],
+ TParseContext* context);
+extern int glslang_parse(TParseContext* context);
+
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.l b/chromium/third_party/angle/src/compiler/translator/glslang.l
new file mode 100644
index 00000000000..518b78df11e
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang.l
@@ -0,0 +1,558 @@
+/*
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+%top{
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+}
+
+%{
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/length_limits.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION \
+ yylloc->first_file = yylloc->last_file = yycolumn; \
+ yylloc->first_line = yylloc->last_line = yylineno;
+
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
+static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
+static int ES2_ident_ES3_keyword(TParseContext *context, int token);
+static int uint_constant(TParseContext *context);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
+static int floatsuffix_check(TParseContext* context);
+%}
+
+%option noyywrap nounput never-interactive
+%option yylineno reentrant bison-bridge bison-locations
+%option extra-type="TParseContext*"
+
+D [0-9]
+L [a-zA-Z_]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+O [0-7]
+
+%%
+
+%{
+ TParseContext* context = yyextra;
+%}
+
+"invariant" { return INVARIANT; }
+"highp" { return HIGH_PRECISION; }
+"mediump" { return MEDIUM_PRECISION; }
+"lowp" { return LOW_PRECISION; }
+"precision" { return PRECISION; }
+
+"attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); }
+"const" { return CONST_QUAL; }
+"uniform" { return UNIFORM; }
+"varying" { return ES2_keyword_ES3_reserved(context, VARYING); }
+
+"break" { return BREAK; }
+"continue" { return CONTINUE; }
+"do" { return DO; }
+"for" { return FOR; }
+"while" { return WHILE; }
+
+"if" { return IF; }
+"else" { return ELSE; }
+"switch" { return ES2_reserved_ES3_keyword(context, SWITCH); }
+"case" { return ES2_ident_ES3_keyword(context, CASE); }
+"default" { return ES2_reserved_ES3_keyword(context, DEFAULT); }
+
+"centroid" { return ES2_ident_ES3_keyword(context, CENTROID); }
+"flat" { return ES2_reserved_ES3_keyword(context, FLAT); }
+"smooth" { return ES2_ident_ES3_keyword(context, SMOOTH); }
+
+"in" { return IN_QUAL; }
+"out" { return OUT_QUAL; }
+"inout" { return INOUT_QUAL; }
+
+"float" { return FLOAT_TYPE; }
+"int" { return INT_TYPE; }
+"uint" { return ES2_ident_ES3_keyword(context, UINT_TYPE); }
+"void" { return VOID_TYPE; }
+"bool" { return BOOL_TYPE; }
+"true" { yylval->lex.b = true; return BOOLCONSTANT; }
+"false" { yylval->lex.b = false; return BOOLCONSTANT; }
+
+"discard" { return DISCARD; }
+"return" { return RETURN; }
+
+"mat2" { return MATRIX2; }
+"mat3" { return MATRIX3; }
+"mat4" { return MATRIX4; }
+
+"mat2x2" { return ES2_ident_ES3_keyword(context, MATRIX2); }
+"mat3x3" { return ES2_ident_ES3_keyword(context, MATRIX3); }
+"mat4x4" { return ES2_ident_ES3_keyword(context, MATRIX4); }
+
+"mat2x3" { return ES2_ident_ES3_keyword(context, MATRIX2x3); }
+"mat3x2" { return ES2_ident_ES3_keyword(context, MATRIX3x2); }
+"mat2x4" { return ES2_ident_ES3_keyword(context, MATRIX2x4); }
+"mat4x2" { return ES2_ident_ES3_keyword(context, MATRIX4x2); }
+"mat3x4" { return ES2_ident_ES3_keyword(context, MATRIX3x4); }
+"mat4x3" { return ES2_ident_ES3_keyword(context, MATRIX4x3); }
+
+"vec2" { return VEC2; }
+"vec3" { return VEC3; }
+"vec4" { return VEC4; }
+"ivec2" { return IVEC2; }
+"ivec3" { return IVEC3; }
+"ivec4" { return IVEC4; }
+"bvec2" { return BVEC2; }
+"bvec3" { return BVEC3; }
+"bvec4" { return BVEC4; }
+"uvec2" { return ES2_ident_ES3_keyword(context, UVEC2); }
+"uvec3" { return ES2_ident_ES3_keyword(context, UVEC3); }
+"uvec4" { return ES2_ident_ES3_keyword(context, UVEC4); }
+
+"sampler2D" { return SAMPLER2D; }
+"samplerCube" { return SAMPLERCUBE; }
+"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; }
+"sampler3D" { return ES2_reserved_ES3_keyword(context, SAMPLER3D); }
+"sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+"sampler2DRect" { return SAMPLER2DRECT; }
+"sampler2DArray" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); }
+"isampler2D" { return ES2_ident_ES3_keyword(context, ISAMPLER2D); }
+"isampler3D" { return ES2_ident_ES3_keyword(context, ISAMPLER3D); }
+"isamplerCube" { return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); }
+"isampler2DArray" { return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); }
+"usampler2D" { return ES2_ident_ES3_keyword(context, USAMPLER2D); }
+"usampler3D" { return ES2_ident_ES3_keyword(context, USAMPLER3D); }
+"usamplerCube" { return ES2_ident_ES3_keyword(context, USAMPLERCUBE); }
+"usampler2DArray" { return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); }
+"sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+"samplerCubeShadow" { return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); }
+"sampler2DArrayShadow" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+
+"struct" { return STRUCT; }
+
+"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); }
+
+ /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
+"coherent" |
+"restrict" |
+"readonly" |
+"writeonly" |
+"resource" |
+"atomic_uint" |
+"noperspective" |
+"patch" |
+"sample" |
+"subroutine" |
+"common" |
+"partition" |
+"active" |
+
+"filter" |
+"image1D" |
+"image2D" |
+"image3D" |
+"imageCube" |
+"iimage1D" |
+"iimage2D" |
+"iimage3D" |
+"iimageCube" |
+"uimage1D" |
+"uimage2D" |
+"uimage3D" |
+"uimageCube" |
+"image1DArray" |
+"image2DArray" |
+"iimage1DArray" |
+"iimage2DArray" |
+"uimage1DArray" |
+"uimage2DArray" |
+"image1DShadow" |
+"image2DShadow" |
+"image1DArrayShadow" |
+"image2DArrayShadow" |
+"imageBuffer" |
+"iimageBuffer" |
+"uimageBuffer" |
+
+"sampler1DArray" |
+"sampler1DArrayShadow" |
+"isampler1D" |
+"isampler1DArray" |
+"usampler1D" |
+"usampler1DArray" |
+"isampler2DRect" |
+"usampler2DRect" |
+"samplerBuffer" |
+"isamplerBuffer" |
+"usamplerBuffer" |
+"sampler2DMS" |
+"isampler2DMS" |
+"usampler2DMS" |
+"sampler2DMSArray" |
+"isampler2DMSArray" |
+"usampler2DMSArray" {
+ if (context->shaderVersion < 300) {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+ return reserved_word(yyscanner);
+}
+
+ /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
+"packed" {
+ if (context->shaderVersion >= 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return reserved_word(yyscanner);
+}
+
+ /* Reserved keywords */
+"asm" |
+
+"class" |
+"union" |
+"enum" |
+"typedef" |
+"template" |
+"this" |
+
+"goto" |
+
+"inline" |
+"noinline" |
+"volatile" |
+"public" |
+"static" |
+"extern" |
+"external" |
+"interface" |
+
+"long" |
+"short" |
+"double" |
+"half" |
+"fixed" |
+"unsigned" |
+"superp" |
+
+"input" |
+"output" |
+
+"hvec2" |
+"hvec3" |
+"hvec4" |
+"dvec2" |
+"dvec3" |
+"dvec4" |
+"fvec2" |
+"fvec3" |
+"fvec4" |
+
+"sampler1D" |
+"sampler1DShadow" |
+"sampler2DRectShadow" |
+
+"sizeof" |
+"cast" |
+
+"namespace" |
+"using" { return reserved_word(yyscanner); }
+
+{L}({L}|{D})* {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+
+0[xX]{H}+ { return int_constant(yyscanner); }
+0{O}+ { return int_constant(yyscanner); }
+{D}+ { return int_constant(yyscanner); }
+
+0[xX]{H}+[uU] { return uint_constant(context); }
+0{O}+[uU] { return uint_constant(context); }
+{D}+[uU] { return uint_constant(context); }
+
+{D}+{E} { return float_constant(yyscanner); }
+{D}+"."{D}*({E})? { return float_constant(yyscanner); }
+"."{D}+({E})? { return float_constant(yyscanner); }
+
+{D}+{E}[fF] { return floatsuffix_check(context); }
+{D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); }
+"."{D}+({E})?[fF] { return floatsuffix_check(context); }
+
+"+=" { return ADD_ASSIGN; }
+"-=" { return SUB_ASSIGN; }
+"*=" { return MUL_ASSIGN; }
+"/=" { return DIV_ASSIGN; }
+"%=" { return MOD_ASSIGN; }
+"<<=" { return LEFT_ASSIGN; }
+">>=" { return RIGHT_ASSIGN; }
+"&=" { return AND_ASSIGN; }
+"^=" { return XOR_ASSIGN; }
+"|=" { return OR_ASSIGN; }
+
+"++" { return INC_OP; }
+"--" { return DEC_OP; }
+"&&" { return AND_OP; }
+"||" { return OR_OP; }
+"^^" { return XOR_OP; }
+"<=" { return LE_OP; }
+">=" { return GE_OP; }
+"==" { return EQ_OP; }
+"!=" { return NE_OP; }
+"<<" { return LEFT_OP; }
+">>" { return RIGHT_OP; }
+";" { return SEMICOLON; }
+("{"|"<%") { return LEFT_BRACE; }
+("}"|"%>") { return RIGHT_BRACE; }
+"," { return COMMA; }
+":" { return COLON; }
+"=" { return EQUAL; }
+"(" { return LEFT_PAREN; }
+")" { return RIGHT_PAREN; }
+("["|"<:") { return LEFT_BRACKET; }
+("]"|":>") { return RIGHT_BRACKET; }
+"." { return DOT; }
+"!" { return BANG; }
+"-" { return DASH; }
+"~" { return TILDE; }
+"+" { return PLUS; }
+"*" { return STAR; }
+"/" { return SLASH; }
+"%" { return PERCENT; }
+"<" { return LEFT_ANGLE; }
+">" { return RIGHT_ANGLE; }
+"|" { return VERTICAL_BAR; }
+"^" { return CARET; }
+"&" { return AMPERSAND; }
+"?" { return QUESTION; }
+
+[ \t\v\n\f\r] { }
+<<EOF>> { yyterminate(); }
+. { assert(false); return 0; }
+
+%%
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ pp::Token token;
+ yyget_extra(yyscanner)->preprocessor.lex(&token);
+ yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
+ if (len < max_size)
+ memcpy(buf, token.text.c_str(), len);
+ yyset_column(token.location.file, yyscanner);
+ yyset_lineno(token.location.line, yyscanner);
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion);
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ token = TYPE_NAME;
+ }
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(*yylloc, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+int ES2_reserved_ES3_keyword(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_keyword_ES3_reserved(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion >= 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_ident_ES3_keyword(TParseContext *context, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name
+ if (context->shaderVersion < 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+int uint_constant(TParseContext *context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
+ context->recover();
+ return 0;
+ }
+
+ if (!atoi_clamp(yytext, &(yylval->lex.i)))
+ yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+
+ return UINTCONSTANT;
+}
+
+int floatsuffix_check(TParseContext* context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
+ context->recover();
+ return 0;
+ }
+
+ if (!atof_clamp(yytext, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext, "");
+
+ return(FLOATCONSTANT);
+}
+
+void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) {
+ context->error(*lloc, reason, yyget_text(context->scanner));
+ context->recover();
+}
+
+int int_constant(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ if (!atoi_clamp(yytext, &(yylval->lex.i)))
+ yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+ return INTCONSTANT;
+}
+
+int float_constant(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ if (!atof_clamp(yytext, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext, "");
+ return FLOATCONSTANT;
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context, &scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ yylex_destroy(scanner);
+
+ return 0;
+}
+
+int glslang_scan(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL, context->scanner);
+ yyset_column(0, context->scanner);
+ yyset_lineno(1, context->scanner);
+
+ // Initialize preprocessor.
+ if (!context->preprocessor.init(count, string, length))
+ return 1;
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+ }
+ if (context->fragmentPrecisionHigh)
+ context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec));
+
+ return 0;
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.y b/chromium/third_party/angle/src/compiler/translator/glslang.y
new file mode 100644
index 00000000000..8ebf2d1f641
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang.y
@@ -0,0 +1,1951 @@
+/*
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Yacc grammar for GLSL ES.
+Based on ANSI C Yacc grammar:
+http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
+*/
+
+%{
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ParseContext.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+#define YYLEX_PARAM context->scanner
+
+%}
+%expect 1 /* One shift reduce conflict because of if | else */
+%pure-parser
+%parse-param {TParseContext* context}
+%locations
+
+%code requires {
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+}
+
+%union {
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+}
+
+%{
+extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
+extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason);
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ } \
+ else { \
+ (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \
+ } \
+ } while (0)
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define ES2_ONLY(S, L) { \
+ if (context->shaderVersion != 100) { \
+ context->error(L, " supported in GLSL ES 1.00 only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define ES3_ONLY(TOKEN, LINE, REASON) { \
+ if (context->shaderVersion != 300) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \
+ context->recover(); \
+ } \
+}
+%}
+
+%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
+%token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3
+%token <lex> CENTROID FLAT SMOOTH
+%token <lex> STRUCT VOID_TYPE WHILE
+%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY
+%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
+%token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY
+%token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW
+%token <lex> LAYOUT
+
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT
+%token <lex> FIELD_SELECTION
+%token <lex> LEFT_OP RIGHT_OP
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token <lex> SUB_ASSIGN
+
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+%type <lex> identifier
+%type <interm> assignment_operator unary_operator
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
+%type <interm.intermTypedNode> expression integer_expression assignment_expression
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
+%type <interm.intermTypedNode> relational_expression equality_expression
+%type <interm.intermTypedNode> conditional_expression constant_expression
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
+%type <interm.intermTypedNode> function_call initializer condition conditionopt
+
+%type <interm.intermNode> translation_unit function_definition
+%type <interm.intermNode> statement simple_statement
+%type <interm.intermAggregate> statement_list compound_statement
+%type <interm.intermNode> declaration_statement selection_statement expression_statement
+%type <interm.intermNode> declaration external_declaration
+%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
+%type <interm.nodePair> selection_rest_statement for_rest_statement
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
+%type <interm> single_declaration init_declarator_list
+
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
+%type <interm.qualifier> parameter_qualifier parameter_type_qualifier
+%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id
+
+%type <interm.precision> precision_qualifier
+%type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier
+%type <interm.type> type_specifier_no_prec type_specifier_nonarray
+%type <interm.type> struct_specifier
+%type <interm.field> struct_declarator
+%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
+%type <interm.function> function_header function_declarator function_identifier
+%type <interm.function> function_header_with_parameters function_call_header
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
+%type <interm> function_call_or_method
+
+%type <lex> enter_struct
+
+%start translation_unit
+%%
+
+identifier
+ : IDENTIFIER
+ | TYPE_NAME
+
+variable_identifier
+ : IDENTIFIER {
+ // The symbol table search was done in the lexical phase
+ const TSymbol *symbol = $1.symbol;
+ const TVariable *variable = 0;
+
+ if (!symbol)
+ {
+ context->error(@1, "undeclared identifier", $1.string->c_str());
+ context->recover();
+ }
+ else if (!symbol->isVariable())
+ {
+ context->error(@1, "variable expected", $1.string->c_str());
+ context->recover();
+ }
+ else
+ {
+ variable = static_cast<const TVariable*>(symbol);
+
+ if (context->symbolTable.findBuiltIn(variable->getName(), context->shaderVersion) &&
+ !variable->getExtension().empty() &&
+ context->extensionErrorCheck(@1, variable->getExtension()))
+ {
+ context->recover();
+ }
+ }
+
+ if (!variable)
+ {
+ TType type(EbtFloat, EbpUndefined);
+ TVariable *fakeVariable = new TVariable($1.string, type);
+ context->symbolTable.declare(*fakeVariable);
+ variable = fakeVariable;
+ }
+
+ if (variable->getType().getQualifier() == EvqConst)
+ {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ $$ = context->intermediate.addConstantUnion(constArray, t, @1);
+ }
+ else
+ {
+ $$ = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ @1);
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+ }
+ ;
+
+primary_expression
+ : variable_identifier {
+ $$ = $1;
+ }
+ | INTCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst($1.i);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1);
+ }
+ | UINTCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setUConst($1.u);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1);
+ }
+ | FLOATCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst($1.f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
+ }
+ | BOOLCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst($1.b);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1);
+ }
+ | LEFT_PAREN expression RIGHT_PAREN {
+ $$ = $2;
+ }
+ ;
+
+postfix_expression
+ : primary_expression {
+ $$ = $1;
+ }
+ | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
+ $$ = context->addIndexExpression($1, @2, $3);
+ }
+ | function_call {
+ $$ = $1;
+ }
+ | postfix_expression DOT identifier {
+ $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3);
+ }
+ | postfix_expression INC_OP {
+ if (context->lValueErrorCheck(@2, "++", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2);
+ if ($$ == 0) {
+ context->unaryOpError(@2, "++", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | postfix_expression DEC_OP {
+ if (context->lValueErrorCheck(@2, "--", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2);
+ if ($$ == 0) {
+ context->unaryOpError(@2, "--", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+integer_expression
+ : expression {
+ if (context->integerErrorCheck($1, "[]"))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+function_call
+ : function_call_or_method {
+ TFunction* fnCall = $1.function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) {
+ $$ = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1);
+ }
+
+ if ($$ == 0) {
+ context->recover();
+ $$ = context->intermediate.setAggregateOperator(0, op, @1);
+ }
+ $$->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck(@1, fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1);
+ if ($$ == 0) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ YYERROR;
+ }
+ } else {
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1);
+ }
+ } else {
+ // This is a real function call
+
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1);
+ $$->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ $$->getAsAggregate()->setUserDefined();
+ $$->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ context->recover();
+ }
+ }
+ }
+ }
+ $$->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ ;
+
+function_call_or_method
+ : function_call_generic {
+ $$ = $1;
+ }
+ | postfix_expression DOT function_call_generic {
+ context->error(@3, "methods are not supported", "");
+ context->recover();
+ $$ = $3;
+ }
+ ;
+
+function_call_generic
+ : function_call_header_with_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ | function_call_header_no_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+function_call_header_no_parameters
+ : function_call_header VOID_TYPE {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ | function_call_header {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ ;
+
+function_call_header_with_parameters
+ : function_call_header assignment_expression {
+ TParameter param = { 0, new TType($2->getType()) };
+ $1->addParameter(param);
+ $$.function = $1;
+ $$.intermNode = $2;
+ }
+ | function_call_header_with_parameters COMMA assignment_expression {
+ TParameter param = { 0, new TType($3->getType()) };
+ $1.function->addParameter(param);
+ $$.function = $1.function;
+ $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2);
+ }
+ ;
+
+function_call_header
+ : function_identifier LEFT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+// Grammar Note: Constructors look like functions, but are recognized as types.
+
+function_identifier
+ : type_specifier_nonarray {
+ $$ = context->addConstructorFunc($1);
+ }
+ | IDENTIFIER {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ ;
+
+unary_expression
+ : postfix_expression {
+ $$ = $1;
+ }
+ | INC_OP unary_expression {
+ if (context->lValueErrorCheck(@1, "++", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1);
+ if ($$ == 0) {
+ context->unaryOpError(@1, "++", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | DEC_OP unary_expression {
+ if (context->lValueErrorCheck(@1, "--", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1);
+ if ($$ == 0) {
+ context->unaryOpError(@1, "--", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | unary_operator unary_expression {
+ if ($1.op != EOpNull) {
+ $$ = context->intermediate.addUnaryMath($1.op, $2, @1);
+ if ($$ == 0) {
+ const char* errorOp = "";
+ switch($1.op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError(@1, errorOp, $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ } else
+ $$ = $2;
+ }
+ ;
+// Grammar Note: No traditional style type casts.
+
+unary_operator
+ : PLUS { $$.op = EOpNull; }
+ | DASH { $$.op = EOpNegative; }
+ | BANG { $$.op = EOpLogicalNot; }
+ ;
+// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+
+multiplicative_expression
+ : unary_expression { $$ = $1; }
+ | multiplicative_expression STAR unary_expression {
+ $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | multiplicative_expression SLASH unary_expression {
+ $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression { $$ = $1; }
+ | additive_expression PLUS multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | additive_expression DASH multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+shift_expression
+ : additive_expression { $$ = $1; }
+ ;
+
+relational_expression
+ : shift_expression { $$ = $1; }
+ | relational_expression LEFT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression RIGHT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression LE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression GE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+equality_expression
+ : relational_expression { $$ = $1; }
+ | equality_expression EQ_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | equality_expression NE_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+and_expression
+ : equality_expression { $$ = $1; }
+ ;
+
+exclusive_or_expression
+ : and_expression { $$ = $1; }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression { $$ = $1; }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression { $$ = $1; }
+ | logical_and_expression AND_OP inclusive_or_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+logical_xor_expression
+ : logical_and_expression { $$ = $1; }
+ | logical_xor_expression XOR_OP logical_and_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+logical_or_expression
+ : logical_xor_expression { $$ = $1; }
+ | logical_or_expression OR_OP logical_xor_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression { $$ = $1; }
+ | logical_or_expression QUESTION expression COLON assignment_expression {
+ if (context->boolErrorCheck(@2, $1))
+ context->recover();
+
+ $$ = context->intermediate.addSelection($1, $3, $5, @2);
+ if ($3->getType() != $5->getType())
+ $$ = 0;
+
+ if ($$ == 0) {
+ context->binaryOpError(@2, ":", $3->getCompleteString(), $5->getCompleteString());
+ context->recover();
+ $$ = $5;
+ }
+ }
+ ;
+
+assignment_expression
+ : conditional_expression { $$ = $1; }
+ | unary_expression assignment_operator assignment_expression {
+ if (context->lValueErrorCheck(@2, "assign", $1))
+ context->recover();
+ $$ = context->intermediate.addAssign($2.op, $1, $3, @2);
+ if ($$ == 0) {
+ context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+assignment_operator
+ : EQUAL { $$.op = EOpAssign; }
+ | MUL_ASSIGN { $$.op = EOpMulAssign; }
+ | DIV_ASSIGN { $$.op = EOpDivAssign; }
+ | ADD_ASSIGN { $$.op = EOpAddAssign; }
+ | SUB_ASSIGN { $$.op = EOpSubAssign; }
+ ;
+
+expression
+ : assignment_expression {
+ $$ = $1;
+ }
+ | expression COMMA assignment_expression {
+ $$ = context->intermediate.addComma($1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $3;
+ }
+ }
+ ;
+
+constant_expression
+ : conditional_expression {
+ if (context->constErrorCheck($1))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+enter_struct
+ : IDENTIFIER LEFT_BRACE {
+ if (context->enterStructDeclaration(@1, *$1.string))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+declaration
+ : function_prototype SEMICOLON {
+ TFunction &function = *($1.function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), @1), @1);
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ $$ = prototype;
+
+ context->symbolTable.pop();
+ }
+ | init_declarator_list SEMICOLON {
+ if ($1.intermAggregate)
+ $1.intermAggregate->setOp(EOpDeclaration);
+ $$ = $1.intermAggregate;
+ }
+ | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
+ if (($2 == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
+ context->error(@1, "precision is not supported in fragment shader", "highp");
+ context->recover();
+ }
+ if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
+ context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type));
+ context->recover();
+ }
+ $$ = 0;
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON {
+ ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks");
+ $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$);
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON {
+ ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks");
+ $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$);
+ }
+ | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON {
+ ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks");
+ $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6);
+ }
+ | type_qualifier SEMICOLON {
+ context->parseGlobalLayoutQualifier($1);
+ $$ = 0;
+ }
+ ;
+
+function_prototype
+ : function_declarator RIGHT_PAREN {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName(), context->shaderVersion));
+ if (prevDec) {
+ if (prevDec->getReturnType() != $1->getReturnType()) {
+ context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
+ context->recover();
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
+ context->error(@2, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = context->symbolTable.find($1->getName(), context->shaderVersion);
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ context->error(@2, "redefinition", $1->getName().c_str(), "function");
+ context->recover();
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ context->symbolTable.getOuterLevel()->insert($1->getName(), *$1);
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ $$.function = $1;
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ context->symbolTable.getOuterLevel()->insert(*$$.function);
+ }
+ ;
+
+function_declarator
+ : function_header {
+ $$ = $1;
+ }
+ | function_header_with_parameters {
+ $$ = $1;
+ }
+ ;
+
+
+function_header_with_parameters
+ : function_header parameter_declaration {
+ // Add the parameter
+ $$ = $1;
+ if ($2.param.type->getBasicType() != EbtVoid)
+ $1->addParameter($2.param);
+ else
+ delete $2.param.type;
+ }
+ | function_header_with_parameters COMMA parameter_declaration {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ($3.param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error(@2, "cannot be an argument type except for '(void)'", "void");
+ context->recover();
+ delete $3.param.type;
+ } else {
+ // Add the parameter
+ $$ = $1;
+ $1->addParameter($3.param);
+ }
+ }
+ ;
+
+function_header
+ : fully_specified_type IDENTIFIER LEFT_PAREN {
+ if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
+ context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type($1);
+ function = new TFunction($2.string, type);
+ $$ = function;
+
+ context->symbolTable.push();
+ }
+ ;
+
+parameter_declarator
+ // Type + name
+ : type_specifier identifier {
+ if ($1.type == EbtVoid) {
+ context->error(@2, "illegal use of type 'void'", $2.string->c_str());
+ context->recover();
+ }
+ if (context->reservedErrorCheck(@2, *$2.string))
+ context->recover();
+ TParameter param = {$2.string, new TType($1)};
+ $$.param = param;
+ }
+ | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck(@3, $1))
+ context->recover();
+
+ if (context->reservedErrorCheck(@2, *$2.string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck(@3, $4, size))
+ context->recover();
+ $1.setArray(true, size);
+
+ TType* type = new TType($1);
+ TParameter param = { $2.string, type };
+ $$.param = param;
+ }
+ ;
+
+parameter_declaration
+ //
+ // The only parameter qualifier a parameter can have are
+ // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
+ //
+
+ //
+ // Type + name
+ //
+ : parameter_type_qualifier parameter_qualifier parameter_declarator {
+ $$ = $3;
+ if (context->paramErrorCheck(@3, $1, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_declarator {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ //
+ // Only type
+ //
+ | parameter_type_qualifier parameter_qualifier parameter_type_specifier {
+ $$ = $3;
+ if (context->paramErrorCheck(@3, $1, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_type_specifier {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ ;
+
+parameter_qualifier
+ : /* empty */ {
+ $$ = EvqIn;
+ }
+ | IN_QUAL {
+ $$ = EvqIn;
+ }
+ | OUT_QUAL {
+ $$ = EvqOut;
+ }
+ | INOUT_QUAL {
+ $$ = EvqInOut;
+ }
+ ;
+
+parameter_type_specifier
+ : type_specifier {
+ TParameter param = { 0, new TType($1) };
+ $$.param = param;
+ }
+ ;
+
+init_declarator_list
+ : single_declaration {
+ $$ = $1;
+ }
+ | init_declarator_list COMMA identifier {
+ $$ = $1;
+ $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, $3.symbol, @3, *$3.string);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET {
+ $$ = $1;
+ context->parseArrayDeclarator($$.type, @3, *$3.string, @4, NULL, NULL);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+ $$.intermAggregate = context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $1.intermNode, $5);
+ }
+ | init_declarator_list COMMA identifier EQUAL initializer {
+ $$ = $1;
+ $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5);
+ }
+ ;
+
+single_declaration
+ : fully_specified_type {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, "");
+ }
+ | fully_specified_type identifier {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
+ }
+ | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
+ context->error(@2, "unsized array declarations not supported", $2.string->c_str());
+ context->recover();
+
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
+ }
+ | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4);
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
+ }
+ | INVARIANT IDENTIFIER {
+ VERTEX_ONLY("invariant declaration", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, @2);
+ if (!$2.symbol)
+ {
+ context->error(@2, "undeclared identifier declared as invariant", $2.string->c_str());
+ context->recover();
+
+ $$.intermAggregate = 0;
+ }
+ else
+ {
+ TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), @2);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
+ }
+ }
+ ;
+
+fully_specified_type
+ : type_specifier {
+ $$ = $1;
+
+ if ($1.array) {
+ context->error(@1, "not supported", "first-class array");
+ context->recover();
+ $1.setArray(false);
+ }
+ }
+ | type_qualifier type_specifier {
+ $$ = context->addFullySpecifiedType($1.qualifier, $1.layoutQualifier, $2);
+ }
+ ;
+
+interpolation_qualifier
+ : SMOOTH {
+ $$.qualifier = EvqSmooth;
+ }
+ | FLAT {
+ $$.qualifier = EvqFlat;
+ }
+ ;
+
+parameter_type_qualifier
+ : CONST_QUAL {
+ $$ = EvqConst;
+ }
+ ;
+
+type_qualifier
+ : ATTRIBUTE {
+ VERTEX_ONLY("attribute", @1);
+ ES2_ONLY("attribute", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqAttribute, @1);
+ }
+ | VARYING {
+ ES2_ONLY("varying", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqVaryingOut, @1);
+ else
+ $$.setBasic(EbtVoid, EvqVaryingIn, @1);
+ }
+ | INVARIANT VARYING {
+ ES2_ONLY("varying", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1);
+ else
+ $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1);
+ }
+ | storage_qualifier {
+ if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) {
+ context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier));
+ context->recover();
+ } else {
+ $$.setBasic(EbtVoid, $1.qualifier, @1);
+ }
+ }
+ | interpolation_qualifier storage_qualifier {
+ $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier);
+ }
+ | interpolation_qualifier {
+ context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier));
+ context->recover();
+
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtVoid, qual, @1);
+ }
+ | layout_qualifier {
+ $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.layoutQualifier = $1;
+ }
+ | layout_qualifier storage_qualifier {
+ $$.setBasic(EbtVoid, $2.qualifier, @2);
+ $$.layoutQualifier = $1;
+ }
+ ;
+
+storage_qualifier
+ : CONST_QUAL {
+ $$.qualifier = EvqConst;
+ }
+ | IN_QUAL {
+ ES3_ONLY("in", @1, "storage qualifier");
+ $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
+ }
+ | OUT_QUAL {
+ ES3_ONLY("out", @1, "storage qualifier");
+ $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
+ }
+ | CENTROID IN_QUAL {
+ ES3_ONLY("centroid in", @1, "storage qualifier");
+ if (context->shaderType == SH_VERTEX_SHADER)
+ {
+ context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
+ context->recover();
+ }
+ $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
+ }
+ | CENTROID OUT_QUAL {
+ ES3_ONLY("centroid out", @1, "storage qualifier");
+ if (context->shaderType == SH_FRAGMENT_SHADER)
+ {
+ context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
+ context->recover();
+ }
+ $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
+ }
+ | UNIFORM {
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ $$.qualifier = EvqUniform;
+ }
+ ;
+
+type_specifier
+ : type_specifier_no_prec {
+ $$ = $1;
+
+ if ($$.precision == EbpUndefined) {
+ $$.precision = context->symbolTable.getDefaultPrecision($1.type);
+ if (context->precisionErrorCheck(@1, $$.precision, $1.type)) {
+ context->recover();
+ }
+ }
+ }
+ | precision_qualifier type_specifier_no_prec {
+ $$ = $2;
+ $$.precision = $1;
+
+ if (!SupportsPrecision($2.type)) {
+ context->error(@1, "illegal type for precision qualifier", getBasicString($2.type));
+ context->recover();
+ }
+ }
+ ;
+
+precision_qualifier
+ : HIGH_PRECISION {
+ $$ = EbpHigh;
+ }
+ | MEDIUM_PRECISION {
+ $$ = EbpMedium;
+ }
+ | LOW_PRECISION {
+ $$ = EbpLow;
+ }
+ ;
+
+layout_qualifier
+ : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN {
+ ES3_ONLY("layout", @1, "qualifier");
+ $$ = $3;
+ }
+ ;
+
+layout_qualifier_id_list
+ : layout_qualifier_id {
+ $$ = $1;
+ }
+ | layout_qualifier_id_list COMMA layout_qualifier_id {
+ $$ = context->joinLayoutQualifiers($1, $3);
+ }
+ ;
+
+layout_qualifier_id
+ : IDENTIFIER {
+ $$ = context->parseLayoutQualifier(*$1.string, @1);
+ }
+ | IDENTIFIER EQUAL INTCONSTANT {
+ $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3);
+ }
+ | IDENTIFIER EQUAL UINTCONSTANT {
+ $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3);
+ }
+ ;
+
+type_specifier_no_prec
+ : type_specifier_nonarray {
+ $$ = $1;
+ }
+ | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck(@2, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck(@2, $3, size))
+ context->recover();
+ $$.setArray(true, size);
+ }
+ }
+ ;
+
+type_specifier_nonarray
+ : VOID_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtVoid, qual, @1);
+ }
+ | FLOAT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ }
+ | INT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ }
+ | UINT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUInt, qual, @1);
+ }
+ | BOOL_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ }
+ | VEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(2);
+ }
+ | VEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(3);
+ }
+ | VEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(4);
+ }
+ | BVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(2);
+ }
+ | BVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(3);
+ }
+ | BVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(4);
+ }
+ | IVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(2);
+ }
+ | IVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(3);
+ }
+ | IVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(4);
+ }
+ | UVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUInt, qual, @1);
+ $$.setAggregate(2);
+ }
+ | UVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUInt, qual, @1);
+ $$.setAggregate(3);
+ }
+ | UVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUInt, qual, @1);
+ $$.setAggregate(4);
+ }
+ | MATRIX2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(2, 2);
+ }
+ | MATRIX3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(3, 3);
+ }
+ | MATRIX4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(4, 4);
+ }
+ | MATRIX2x3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(2, 3);
+ }
+ | MATRIX3x2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(3, 2);
+ }
+ | MATRIX2x4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(2, 4);
+ }
+ | MATRIX4x2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(4, 2);
+ }
+ | MATRIX3x4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(3, 4);
+ }
+ | MATRIX4x3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setMatrix(4, 3);
+ }
+ | SAMPLER2D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2D, qual, @1);
+ }
+ | SAMPLER3D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler3D, qual, @1);
+ }
+ | SAMPLERCUBE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerCube, qual, @1);
+ }
+ | SAMPLER2DARRAY {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DArray, qual, @1);
+ }
+ | ISAMPLER2D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtISampler2D, qual, @1);
+ }
+ | ISAMPLER3D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtISampler3D, qual, @1);
+ }
+ | ISAMPLERCUBE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtISamplerCube, qual, @1);
+ }
+ | ISAMPLER2DARRAY {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtISampler2DArray, qual, @1);
+ }
+ | USAMPLER2D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUSampler2D, qual, @1);
+ }
+ | USAMPLER3D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUSampler3D, qual, @1);
+ }
+ | USAMPLERCUBE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUSamplerCube, qual, @1);
+ }
+ | USAMPLER2DARRAY {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtUSampler2DArray, qual, @1);
+ }
+ | SAMPLER2DSHADOW {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DShadow, qual, @1);
+ }
+ | SAMPLERCUBESHADOW {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerCubeShadow, qual, @1);
+ }
+ | SAMPLER2DARRAYSHADOW {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DArrayShadow, qual, @1);
+ }
+ | SAMPLER_EXTERNAL_OES {
+ if (!context->supportsExtension("GL_OES_EGL_image_external")) {
+ context->error(@1, "unsupported type", "samplerExternalOES");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerExternalOES, qual, @1);
+ }
+ | SAMPLER2DRECT {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error(@1, "unsupported type", "sampler2DRect");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DRect, qual, @1);
+ }
+ | struct_specifier {
+ $$ = $1;
+ $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ | TYPE_NAME {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>($1.symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtStruct, qual, @1);
+ $$.userDef = &structure;
+ }
+ ;
+
+struct_specifier
+ : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ $$ = context->addStructure(@1, @2, $2.string, $5);
+ }
+ | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ $$ = context->addStructure(@1, @$, NewPoolTString(""), $4);
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration {
+ $$ = $1;
+ }
+ | struct_declaration_list struct_declaration {
+ $$ = $1;
+ for (size_t i = 0; i < $2->size(); ++i) {
+ TField* field = (*$2)[i];
+ for (size_t j = 0; j < $$->size(); ++j) {
+ if ((*$$)[j]->name() == field->name()) {
+ context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str());
+ context->recover();
+ }
+ }
+ $$->push_back(field);
+ }
+ }
+ ;
+
+struct_declaration
+ : type_specifier struct_declarator_list SEMICOLON {
+ $$ = context->addStructDeclaratorList($1, $2);
+ }
+ | type_qualifier type_specifier struct_declarator_list SEMICOLON {
+ // ES3 Only, but errors should be handled elsewhere
+ $2.qualifier = $1.qualifier;
+ $2.layoutQualifier = $1.layoutQualifier;
+ $$ = context->addStructDeclaratorList($2, $3);
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator {
+ $$ = NewPoolTFieldList();
+ $$->push_back($1);
+ }
+ | struct_declarator_list COMMA struct_declarator {
+ $$->push_back($3);
+ }
+ ;
+
+struct_declarator
+ : identifier {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ $$ = new TField(type, $1.string, @1);
+ }
+ | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ int size;
+ if (context->arraySizeErrorCheck(@3, $3, size))
+ context->recover();
+ type->setArraySize(size);
+
+ $$ = new TField(type, $1.string, @1);
+ }
+ ;
+
+initializer
+ : assignment_expression { $$ = $1; }
+ ;
+
+declaration_statement
+ : declaration { $$ = $1; }
+ ;
+
+statement
+ : compound_statement { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+// Grammar Note: No labeled statements; 'goto' is not supported.
+
+simple_statement
+ : declaration_statement { $$ = $1; }
+ | expression_statement { $$ = $1; }
+ | selection_statement { $$ = $1; }
+ | iteration_statement { $$ = $1; }
+ | jump_statement { $$ = $1; }
+ ;
+
+compound_statement
+ : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
+ | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
+ if ($3 != 0) {
+ $3->setOp(EOpSequence);
+ $3->setLine(@$);
+ }
+ $$ = $3;
+ }
+ ;
+
+statement_no_new_scope
+ : compound_statement_no_new_scope { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+statement_with_scope
+ : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; }
+ | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; }
+ ;
+
+compound_statement_no_new_scope
+ // Statement that doesn't create a new scope, for selection_statement, iteration_statement
+ : LEFT_BRACE RIGHT_BRACE {
+ $$ = 0;
+ }
+ | LEFT_BRACE statement_list RIGHT_BRACE {
+ if ($2) {
+ $2->setOp(EOpSequence);
+ $2->setLine(@$);
+ }
+ $$ = $2;
+ }
+ ;
+
+statement_list
+ : statement {
+ $$ = context->intermediate.makeAggregate($1, @$);
+ }
+ | statement_list statement {
+ $$ = context->intermediate.growAggregate($1, $2, @$);
+ }
+ ;
+
+expression_statement
+ : SEMICOLON { $$ = 0; }
+ | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
+ ;
+
+selection_statement
+ : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
+ if (context->boolErrorCheck(@1, $3))
+ context->recover();
+ $$ = context->intermediate.addSelection($3, $5, @1);
+ }
+ ;
+
+selection_rest_statement
+ : statement_with_scope ELSE statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ | statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ ;
+
+// Grammar Note: No 'switch'. Switch statements not supported.
+
+condition
+ // In 1996 c++ draft, conditions can include single declarations
+ : expression {
+ $$ = $1;
+ if (context->boolErrorCheck($1->getLine(), $1))
+ context->recover();
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+ if (context->boolErrorCheck(@2, $1))
+ context->recover();
+
+ if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode))
+ $$ = $4;
+ else {
+ context->recover();
+ $$ = 0;
+ }
+ }
+ ;
+
+iteration_statement
+ : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
+ --context->loopNestingLevel;
+ }
+ | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ if (context->boolErrorCheck(@8, $6))
+ context->recover();
+
+ $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
+ --context->loopNestingLevel;
+ }
+ | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
+ --context->loopNestingLevel;
+ }
+ ;
+
+for_init_statement
+ : expression_statement {
+ $$ = $1;
+ }
+ | declaration_statement {
+ $$ = $1;
+ }
+ ;
+
+conditionopt
+ : condition {
+ $$ = $1;
+ }
+ | /* May be null */ {
+ $$ = 0;
+ }
+ ;
+
+for_rest_statement
+ : conditionopt SEMICOLON {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ | conditionopt SEMICOLON expression {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ ;
+
+jump_statement
+ : CONTINUE SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error(@1, "continue statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpContinue, @1);
+ }
+ | BREAK SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error(@1, "break statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpBreak, @1);
+ }
+ | RETURN SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, @1);
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error(@1, "non-void function must return a value", "return");
+ context->recover();
+ }
+ }
+ | RETURN expression SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $2, @1);
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error(@1, "void function cannot return a value", "return");
+ context->recover();
+ } else if (*(context->currentFunctionType) != $2->getType()) {
+ context->error(@1, "function return is not matching type:", "return");
+ context->recover();
+ }
+ }
+ | DISCARD SEMICOLON {
+ FRAG_ONLY("discard", @1);
+ $$ = context->intermediate.addBranch(EOpKill, @1);
+ }
+ ;
+
+// Grammar Note: No 'goto'. Gotos are not supported.
+
+translation_unit
+ : external_declaration {
+ $$ = $1;
+ context->treeRoot = $$;
+ }
+ | translation_unit external_declaration {
+ $$ = context->intermediate.growAggregate($1, $2, @$);
+ context->treeRoot = $$;
+ }
+ ;
+
+external_declaration
+ : function_definition {
+ $$ = $1;
+ }
+ | declaration {
+ $$ = $1;
+ }
+ ;
+
+function_definition
+ : function_prototype {
+ TFunction* function = $1.function;
+
+ const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion);
+
+ if (builtIn)
+ {
+ context->error(@1, "built-in functions cannot be redefined", function->getName().c_str());
+ context->recover();
+ }
+
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName(), context->shaderVersion));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error(@1, "function already has a body", function->getName().c_str());
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error(@1, "function cannot take any parameter(s)", function->getName().c_str());
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error(@1, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.declare(*variable)) {
+ context->error(@1, "redefinition", variable->getName().c_str());
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), @1),
+ @1);
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
+ $1.intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ compound_statement_no_new_scope {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
+ context->recover();
+ }
+
+ $$ = context->intermediate.growAggregate($1.intermAggregate, $3, @$);
+ context->intermediate.setAggregateOperator($$, EOpFunction, @1);
+ $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
+ $$->getAsAggregate()->setType($1.function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ $$->getAsAggregate()->setOptimize(context->pragma().optimize);
+ $$->getAsAggregate()->setDebug(context->pragma().debug);
+
+ context->symbolTable.pop();
+ }
+ ;
+
+%%
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp
new file mode 100644
index 00000000000..5cfbba63eb3
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp
@@ -0,0 +1,3360 @@
+#line 17 "./glslang.l"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+
+
+#line 25 "./glslang_lex.cpp"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void yypop_buffer_state (yyscan_t yyscanner );
+
+static void yyensure_buffer_stack (yyscan_t yyscanner );
+static void yy_load_buffer_state (yyscan_t yyscanner );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap(yyscanner) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 237
+#define YY_END_OF_BUFFER 238
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[813] =
+ { 0,
+ 0, 0, 238, 236, 235, 235, 222, 228, 233, 217,
+ 218, 226, 225, 214, 223, 221, 227, 180, 180, 215,
+ 211, 229, 216, 230, 234, 177, 219, 220, 232, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 212,
+ 231, 213, 224, 208, 194, 213, 202, 197, 192, 200,
+ 190, 201, 191, 186, 193, 185, 179, 180, 0, 183,
+ 0, 220, 212, 219, 209, 205, 207, 206, 210, 177,
+ 198, 204, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 12, 177, 177, 177, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 15, 177,
+ 177, 23, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 199, 203, 0, 189, 185,
+ 0, 188, 182, 0, 184, 178, 195, 196, 177, 136,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 13, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 27, 177, 177, 177, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 24, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 0, 186, 0, 185, 187, 181, 177, 177, 177,
+ 30, 177, 177, 18, 174, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 16, 139, 177, 177, 177,
+ 177, 21, 177, 177, 143, 155, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 152, 4,
+ 35, 36, 37, 177, 177, 177, 177, 177, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 142, 31, 177,
+ 177, 28, 177, 177, 177, 177, 177, 177, 177, 47,
+ 48, 49, 29, 177, 177, 177, 177, 177, 177, 10,
+ 53, 54, 55, 177, 137, 177, 177, 7, 177, 177,
+ 177, 177, 164, 165, 166, 177, 32, 177, 156, 26,
+ 167, 168, 169, 2, 161, 162, 163, 177, 177, 177,
+ 25, 159, 177, 177, 177, 50, 51, 52, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 86,
+ 177, 177, 177, 177, 177, 177, 177, 153, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 138,
+ 177, 177, 176, 56, 57, 58, 177, 177, 14, 177,
+ 91, 177, 177, 177, 177, 89, 177, 177, 177, 154,
+ 149, 92, 177, 177, 177, 177, 177, 177, 144, 177,
+ 177, 177, 78, 38, 41, 43, 42, 39, 45, 44,
+ 46, 40, 177, 177, 177, 177, 160, 135, 177, 177,
+ 147, 177, 177, 177, 34, 87, 173, 22, 148, 77,
+ 177, 158, 17, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 19, 33, 177,
+ 177, 177, 177, 177, 177, 93, 94, 95, 177, 177,
+
+ 177, 177, 177, 3, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 140, 177, 177, 177, 177,
+ 177, 8, 177, 177, 9, 177, 177, 177, 177, 20,
+ 79, 11, 150, 97, 98, 99, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 145, 177,
+ 177, 177, 81, 83, 80, 177, 177, 177, 177, 177,
+ 177, 177, 141, 101, 102, 103, 177, 177, 157, 177,
+ 146, 177, 177, 6, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 96, 151, 1, 177, 177, 177, 177,
+ 177, 175, 177, 90, 5, 170, 59, 62, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 82, 177, 177, 177, 177, 100, 177, 177, 177,
+ 177, 177, 120, 66, 67, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 177, 88, 177,
+ 177, 177, 104, 122, 70, 71, 177, 177, 84, 177,
+ 177, 177, 177, 177, 177, 177, 115, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 129, 177, 177,
+ 177, 177, 60, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 116, 105, 177, 106, 177,
+ 177, 177, 130, 177, 177, 68, 177, 177, 177, 177,
+
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 117,
+ 177, 177, 131, 177, 177, 72, 107, 108, 177, 111,
+ 177, 112, 177, 177, 177, 177, 177, 85, 177, 177,
+ 177, 177, 64, 177, 63, 126, 177, 177, 109, 110,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 124, 127, 118, 177, 65, 177, 177, 177, 177, 177,
+ 177, 177, 177, 125, 128, 177, 177, 121, 69, 177,
+ 177, 171, 177, 177, 177, 74, 177, 177, 123, 73,
+ 177, 177, 177, 177, 177, 177, 132, 177, 177, 177,
+ 177, 177, 177, 133, 177, 177, 177, 75, 177, 134,
+
+ 113, 114, 177, 177, 177, 61, 177, 177, 172, 119,
+ 76, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 20, 20, 21, 21, 22, 23, 24,
+ 25, 26, 27, 1, 28, 29, 30, 31, 32, 33,
+ 34, 34, 34, 34, 34, 34, 35, 34, 36, 34,
+ 34, 37, 38, 34, 39, 34, 34, 40, 34, 34,
+ 41, 1, 42, 43, 44, 1, 45, 46, 47, 48,
+
+ 49, 50, 51, 52, 53, 34, 54, 55, 56, 57,
+ 58, 59, 34, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[73] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+ 3, 2, 2, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 1, 4, 3, 3, 3, 3, 2, 2,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 1, 1,
+ 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[817] =
+ { 0,
+ 0, 0, 941, 942, 942, 942, 915, 48, 69, 942,
+ 942, 914, 66, 942, 65, 63, 913, 82, 136, 911,
+ 942, 82, 911, 60, 942, 0, 942, 942, 67, 58,
+ 51, 68, 75, 61, 105, 877, 114, 79, 67, 44,
+ 89, 871, 101, 884, 121, 127, 136, 143, 36, 942,
+ 112, 942, 942, 942, 942, 942, 942, 942, 942, 942,
+ 942, 942, 942, 158, 942, 163, 163, 0, 199, 942,
+ 0, 942, 942, 942, 907, 942, 942, 942, 906, 0,
+ 942, 942, 868, 873, 80, 870, 878, 877, 864, 867,
+ 878, 171, 872, 860, 857, 870, 857, 854, 854, 860,
+
+ 75, 176, 854, 864, 850, 856, 859, 860, 0, 852,
+ 862, 177, 861, 856, 837, 105, 841, 854, 845, 112,
+ 838, 178, 850, 852, 185, 841, 838, 827, 836, 177,
+ 185, 840, 836, 838, 827, 830, 124, 145, 197, 839,
+ 827, 839, 190, 832, 831, 942, 942, 239, 942, 220,
+ 256, 942, 942, 263, 270, 185, 942, 942, 830, 0,
+ 826, 821, 825, 834, 831, 243, 815, 815, 826, 818,
+ 143, 828, 825, 825, 823, 820, 812, 818, 805, 803,
+ 815, 801, 817, 0, 814, 802, 809, 806, 810, 811,
+ 804, 801, 790, 789, 802, 805, 793, 801, 789, 795,
+
+ 786, 244, 791, 794, 785, 792, 781, 785, 776, 790,
+ 789, 780, 786, 235, 770, 773, 771, 781, 771, 766,
+ 764, 766, 776, 762, 764, 761, 772, 771, 774, 756,
+ 244, 764, 760, 758, 767, 746, 281, 764, 766, 755,
+ 747, 291, 298, 306, 317, 942, 942, 744, 754, 753,
+ 0, 751, 311, 0, 0, 744, 742, 742, 743, 738,
+ 746, 735, 752, 741, 322, 0, 0, 735, 745, 744,
+ 744, 0, 729, 325, 0, 0, 731, 328, 738, 739,
+ 730, 724, 723, 724, 723, 723, 334, 718, 0, 0,
+ 714, 713, 712, 714, 715, 720, 714, 710, 723, 718,
+
+ 718, 716, 715, 709, 703, 705, 704, 708, 700, 703,
+ 698, 706, 711, 699, 696, 708, 699, 0, 0, 705,
+ 701, 0, 693, 693, 698, 689, 696, 337, 693, 0,
+ 0, 0, 0, 683, 695, 694, 693, 694, 694, 0,
+ 0, 0, 0, 681, 0, 689, 680, 0, 679, 680,
+ 674, 684, 0, 0, 0, 675, 0, 671, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 681, 341, 680,
+ 0, 0, 678, 674, 671, 0, 0, 0, 663, 343,
+ 346, 355, 668, 664, 669, 660, 658, 671, 656, 0,
+ 656, 669, 658, 654, 660, 655, 662, 0, 660, 657,
+
+ 661, 645, 643, 646, 652, 658, 653, 652, 640, 0,
+ 642, 643, 0, 0, 0, 0, 640, 643, 0, 637,
+ 0, 650, 630, 639, 634, 0, 627, 627, 640, 0,
+ 642, 0, 359, 655, 654, 653, 620, 619, 0, 636,
+ 635, 630, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 619, 632, 619, 616, 0, 0, 621, 620,
+ 0, 617, 624, 623, 0, 609, 0, 0, 0, 0,
+ 606, 0, 0, 605, 616, 362, 609, 615, 614, 611,
+ 606, 603, 596, 596, 609, 594, 606, 0, 0, 599,
+ 622, 621, 620, 587, 586, 355, 356, 0, 598, 601,
+
+ 599, 588, 584, 0, 596, 593, 592, 582, 581, 571,
+ 588, 574, 369, 582, 585, 0, 602, 601, 600, 567,
+ 566, 0, 580, 567, 0, 577, 570, 571, 574, 0,
+ 0, 0, 0, 594, 593, 0, 570, 573, 558, 565,
+ 556, 563, 564, 564, 563, 549, 379, 561, 0, 562,
+ 551, 550, 0, 0, 0, 575, 574, 573, 540, 539,
+ 535, 543, 0, 571, 570, 0, 547, 550, 0, 386,
+ 0, 528, 537, 0, 533, 532, 541, 541, 529, 543,
+ 527, 541, 536, 0, 0, 0, 553, 552, 551, 518,
+ 517, 0, 517, 0, 0, 362, 382, 541, 527, 530,
+
+ 513, 525, 513, 512, 521, 521, 538, 537, 536, 503,
+ 502, 0, 502, 503, 502, 512, 0, 515, 511, 513,
+ 509, 496, 527, 377, 0, 504, 507, 499, 491, 498,
+ 489, 510, 498, 494, 496, 494, 494, 493, 0, 481,
+ 480, 490, 0, 510, 390, 0, 487, 490, 0, 490,
+ 489, 473, 465, 473, 463, 471, 0, 468, 467, 488,
+ 476, 474, 474, 458, 461, 475, 459, 490, 470, 471,
+ 468, 465, 475, 452, 466, 465, 449, 448, 447, 468,
+ 456, 454, 454, 435, 434, 0, 462, 434, 460, 432,
+ 436, 435, 466, 446, 443, 0, 442, 445, 441, 443,
+
+ 427, 424, 437, 422, 423, 430, 424, 413, 412, 0,
+ 418, 417, 448, 428, 425, 0, 0, 0, 421, 0,
+ 420, 0, 426, 425, 409, 406, 407, 0, 399, 407,
+ 397, 403, 424, 403, 0, 0, 415, 414, 0, 0,
+ 413, 412, 396, 393, 394, 408, 407, 384, 383, 389,
+ 0, 0, 410, 382, 408, 400, 392, 378, 60, 89,
+ 105, 143, 173, 0, 0, 216, 217, 0, 0, 222,
+ 243, 0, 244, 234, 259, 0, 291, 330, 0, 0,
+ 323, 311, 323, 315, 361, 362, 0, 363, 348, 389,
+ 355, 358, 359, 0, 378, 380, 371, 0, 392, 0,
+
+ 0, 0, 373, 374, 368, 0, 369, 370, 0, 0,
+ 0, 942, 434, 437, 438, 439
+ } ;
+
+static yyconst flex_int16_t yy_def[817] =
+ { 0,
+ 812, 1, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 813, 812, 812, 812, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 814, 812, 815, 18, 19, 812, 812,
+ 816, 812, 812, 812, 812, 812, 812, 812, 812, 813,
+ 812, 812, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 812, 812, 812, 812, 815,
+ 812, 812, 812, 812, 812, 816, 812, 812, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 812, 812, 812, 812, 812, 812, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 813, 813, 813, 813,
+ 813, 0, 812, 812, 812, 812
+ } ;
+
+static yyconst flex_int16_t yy_nxt[1015] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 19, 19, 19,
+ 19, 20, 21, 22, 23, 24, 25, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 27, 28, 29, 26, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 26, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 26, 26, 26, 50, 51,
+ 52, 53, 55, 56, 57, 60, 62, 64, 64, 64,
+ 64, 64, 64, 64, 78, 79, 73, 144, 117, 63,
+ 61, 81, 118, 58, 66, 145, 67, 67, 67, 67,
+
+ 67, 67, 68, 74, 83, 75, 76, 777, 86, 82,
+ 87, 115, 89, 69, 88, 97, 90, 98, 84, 85,
+ 70, 71, 91, 93, 116, 92, 99, 94, 109, 180,
+ 69, 110, 95, 119, 111, 112, 146, 161, 96, 113,
+ 181, 162, 114, 778, 70, 122, 120, 71, 66, 100,
+ 68, 68, 68, 68, 68, 68, 68, 101, 106, 102,
+ 123, 200, 103, 124, 205, 126, 107, 69, 104, 201,
+ 206, 779, 127, 128, 70, 133, 129, 108, 134, 229,
+ 230, 147, 130, 131, 69, 132, 135, 141, 137, 148,
+ 149, 142, 138, 136, 151, 152, 139, 231, 70, 140,
+
+ 143, 153, 812, 260, 261, 232, 148, 149, 154, 780,
+ 154, 151, 152, 155, 155, 155, 155, 155, 155, 155,
+ 182, 220, 169, 247, 208, 153, 170, 171, 812, 213,
+ 222, 192, 781, 183, 193, 194, 221, 209, 195, 210,
+ 196, 233, 238, 223, 239, 214, 215, 247, 242, 234,
+ 242, 151, 152, 243, 243, 243, 243, 243, 243, 243,
+ 291, 292, 293, 782, 783, 244, 784, 244, 151, 152,
+ 245, 245, 245, 245, 245, 245, 245, 155, 155, 155,
+ 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+ 155, 254, 305, 323, 785, 786, 306, 330, 331, 332,
+
+ 787, 324, 246, 788, 255, 243, 243, 243, 243, 243,
+ 243, 243, 243, 243, 243, 243, 243, 243, 243, 246,
+ 245, 245, 245, 245, 245, 245, 245, 341, 342, 343,
+ 149, 245, 245, 245, 245, 245, 245, 245, 353, 354,
+ 355, 361, 362, 363, 365, 366, 367, 149, 789, 152,
+ 376, 377, 378, 414, 415, 416, 434, 435, 436, 444,
+ 445, 446, 447, 448, 449, 790, 152, 791, 792, 437,
+ 438, 450, 451, 452, 491, 492, 493, 517, 518, 519,
+ 793, 794, 539, 541, 556, 557, 558, 494, 495, 629,
+ 520, 521, 540, 542, 587, 588, 589, 559, 560, 630,
+
+ 561, 607, 608, 609, 659, 795, 796, 590, 591, 631,
+ 797, 660, 798, 661, 610, 611, 632, 679, 633, 634,
+ 799, 800, 801, 802, 680, 803, 681, 804, 805, 806,
+ 807, 808, 809, 810, 811, 80, 80, 80, 64, 150,
+ 156, 156, 776, 775, 774, 773, 772, 771, 770, 769,
+ 768, 767, 766, 765, 764, 763, 762, 761, 760, 759,
+ 758, 757, 756, 755, 754, 753, 752, 751, 750, 749,
+ 748, 747, 746, 745, 744, 743, 742, 741, 740, 739,
+ 738, 737, 736, 735, 734, 733, 732, 731, 730, 729,
+ 728, 727, 726, 725, 724, 723, 722, 721, 720, 719,
+
+ 718, 717, 716, 715, 714, 713, 712, 711, 710, 709,
+ 708, 707, 706, 705, 704, 703, 702, 701, 700, 699,
+ 698, 697, 696, 695, 694, 693, 692, 691, 690, 689,
+ 688, 687, 686, 685, 684, 683, 682, 678, 677, 676,
+ 675, 674, 673, 672, 671, 670, 669, 668, 667, 666,
+ 665, 664, 663, 662, 658, 657, 656, 655, 654, 653,
+ 652, 651, 650, 649, 648, 647, 646, 645, 644, 643,
+ 642, 641, 640, 639, 638, 637, 636, 635, 628, 627,
+ 626, 625, 624, 623, 622, 621, 620, 619, 618, 617,
+ 616, 615, 614, 613, 612, 606, 605, 604, 603, 602,
+
+ 601, 600, 599, 598, 597, 596, 595, 594, 593, 592,
+ 586, 585, 584, 583, 582, 581, 580, 579, 578, 577,
+ 576, 575, 574, 573, 572, 571, 570, 569, 568, 567,
+ 566, 565, 564, 563, 562, 555, 554, 553, 552, 551,
+ 550, 549, 548, 547, 546, 545, 544, 543, 538, 537,
+ 536, 535, 534, 533, 532, 531, 530, 529, 528, 527,
+ 526, 525, 524, 523, 522, 516, 515, 514, 513, 512,
+ 511, 510, 509, 508, 507, 506, 505, 504, 503, 502,
+ 501, 500, 499, 498, 497, 496, 490, 489, 488, 487,
+ 486, 485, 484, 483, 482, 481, 480, 479, 478, 477,
+
+ 476, 475, 474, 473, 472, 471, 470, 469, 468, 467,
+ 466, 465, 464, 463, 462, 461, 460, 459, 458, 457,
+ 456, 455, 454, 453, 443, 442, 441, 440, 439, 433,
+ 432, 431, 430, 429, 428, 427, 426, 425, 424, 423,
+ 422, 421, 420, 419, 418, 417, 413, 412, 411, 410,
+ 409, 408, 407, 406, 405, 404, 403, 402, 401, 400,
+ 399, 398, 397, 396, 395, 394, 393, 392, 391, 390,
+ 389, 388, 387, 386, 385, 384, 383, 382, 381, 380,
+ 379, 375, 374, 373, 372, 371, 370, 369, 368, 364,
+ 360, 359, 358, 357, 356, 352, 351, 350, 349, 348,
+
+ 347, 346, 345, 344, 340, 339, 338, 337, 336, 335,
+ 334, 333, 329, 328, 327, 326, 325, 322, 321, 320,
+ 319, 318, 317, 316, 315, 314, 313, 312, 311, 310,
+ 309, 308, 307, 304, 303, 302, 301, 300, 299, 298,
+ 297, 296, 295, 294, 290, 289, 288, 287, 286, 285,
+ 284, 283, 282, 281, 280, 279, 278, 277, 276, 275,
+ 274, 273, 272, 271, 270, 269, 268, 267, 266, 265,
+ 264, 263, 262, 259, 258, 257, 256, 253, 252, 251,
+ 250, 249, 248, 241, 240, 237, 236, 235, 228, 227,
+ 226, 225, 224, 219, 218, 217, 216, 212, 211, 207,
+
+ 204, 203, 202, 199, 198, 197, 191, 190, 189, 188,
+ 187, 186, 185, 184, 179, 178, 177, 176, 175, 174,
+ 173, 172, 168, 167, 166, 165, 164, 163, 160, 159,
+ 158, 157, 125, 121, 105, 77, 72, 65, 59, 54,
+ 812, 3, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812
+ } ;
+
+static yyconst flex_int16_t yy_chk[1015] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 8, 8, 9, 13, 15, 16, 16, 16,
+ 16, 16, 16, 16, 24, 24, 22, 49, 40, 15,
+ 13, 29, 40, 9, 18, 49, 18, 18, 18, 18,
+
+ 18, 18, 18, 22, 30, 22, 22, 759, 31, 29,
+ 31, 39, 32, 18, 31, 34, 32, 34, 30, 30,
+ 18, 18, 32, 33, 39, 32, 34, 33, 38, 101,
+ 18, 38, 33, 41, 38, 38, 51, 85, 33, 38,
+ 101, 85, 38, 760, 18, 43, 41, 18, 19, 35,
+ 19, 19, 19, 19, 19, 19, 19, 35, 37, 35,
+ 43, 116, 35, 43, 120, 45, 37, 19, 35, 116,
+ 120, 761, 45, 45, 19, 46, 45, 37, 46, 137,
+ 137, 51, 45, 45, 19, 45, 46, 48, 47, 64,
+ 64, 48, 47, 46, 66, 66, 47, 138, 19, 47,
+
+ 48, 67, 67, 171, 171, 138, 64, 64, 69, 762,
+ 69, 66, 66, 69, 69, 69, 69, 69, 69, 69,
+ 102, 130, 92, 156, 122, 67, 92, 92, 67, 125,
+ 131, 112, 763, 102, 112, 112, 130, 122, 112, 122,
+ 112, 139, 143, 131, 143, 125, 125, 156, 148, 139,
+ 148, 150, 150, 148, 148, 148, 148, 148, 148, 148,
+ 202, 202, 202, 766, 767, 151, 770, 151, 150, 150,
+ 151, 151, 151, 151, 151, 151, 151, 154, 154, 154,
+ 154, 154, 154, 154, 155, 155, 155, 155, 155, 155,
+ 155, 166, 214, 231, 771, 773, 214, 237, 237, 237,
+
+ 774, 231, 155, 775, 166, 242, 242, 242, 242, 242,
+ 242, 242, 243, 243, 243, 243, 243, 243, 243, 155,
+ 244, 244, 244, 244, 244, 244, 244, 253, 253, 253,
+ 243, 245, 245, 245, 245, 245, 245, 245, 265, 265,
+ 265, 274, 274, 274, 278, 278, 278, 243, 777, 245,
+ 287, 287, 287, 328, 328, 328, 369, 369, 369, 380,
+ 380, 380, 381, 381, 381, 778, 245, 781, 782, 369,
+ 369, 382, 382, 382, 433, 433, 433, 476, 476, 476,
+ 783, 784, 496, 497, 513, 513, 513, 433, 433, 596,
+ 476, 476, 496, 497, 547, 547, 547, 513, 513, 596,
+
+ 513, 570, 570, 570, 624, 785, 786, 547, 547, 597,
+ 788, 624, 789, 624, 570, 570, 597, 645, 597, 597,
+ 790, 791, 792, 793, 645, 795, 645, 796, 797, 799,
+ 803, 804, 805, 807, 808, 813, 813, 813, 814, 815,
+ 816, 816, 758, 757, 756, 755, 754, 753, 750, 749,
+ 748, 747, 746, 745, 744, 743, 742, 741, 738, 737,
+ 734, 733, 732, 731, 730, 729, 727, 726, 725, 724,
+ 723, 721, 719, 715, 714, 713, 712, 711, 709, 708,
+ 707, 706, 705, 704, 703, 702, 701, 700, 699, 698,
+ 697, 695, 694, 693, 692, 691, 690, 689, 688, 687,
+
+ 685, 684, 683, 682, 681, 680, 679, 678, 677, 676,
+ 675, 674, 673, 672, 671, 670, 669, 668, 667, 666,
+ 665, 664, 663, 662, 661, 660, 659, 658, 656, 655,
+ 654, 653, 652, 651, 650, 648, 647, 644, 642, 641,
+ 640, 638, 637, 636, 635, 634, 633, 632, 631, 630,
+ 629, 628, 627, 626, 623, 622, 621, 620, 619, 618,
+ 616, 615, 614, 613, 611, 610, 609, 608, 607, 606,
+ 605, 604, 603, 602, 601, 600, 599, 598, 593, 591,
+ 590, 589, 588, 587, 583, 582, 581, 580, 579, 578,
+ 577, 576, 575, 573, 572, 568, 567, 565, 564, 562,
+
+ 561, 560, 559, 558, 557, 556, 552, 551, 550, 548,
+ 546, 545, 544, 543, 542, 541, 540, 539, 538, 537,
+ 535, 534, 529, 528, 527, 526, 524, 523, 521, 520,
+ 519, 518, 517, 515, 514, 512, 511, 510, 509, 508,
+ 507, 506, 505, 503, 502, 501, 500, 499, 495, 494,
+ 493, 492, 491, 490, 487, 486, 485, 484, 483, 482,
+ 481, 480, 479, 478, 477, 475, 474, 471, 466, 464,
+ 463, 462, 460, 459, 456, 455, 454, 453, 442, 441,
+ 440, 438, 437, 436, 435, 434, 431, 429, 428, 427,
+ 425, 424, 423, 422, 420, 418, 417, 412, 411, 409,
+
+ 408, 407, 406, 405, 404, 403, 402, 401, 400, 399,
+ 397, 396, 395, 394, 393, 392, 391, 389, 388, 387,
+ 386, 385, 384, 383, 379, 375, 374, 373, 370, 368,
+ 358, 356, 352, 351, 350, 349, 347, 346, 344, 339,
+ 338, 337, 336, 335, 334, 329, 327, 326, 325, 324,
+ 323, 321, 320, 317, 316, 315, 314, 313, 312, 311,
+ 310, 309, 308, 307, 306, 305, 304, 303, 302, 301,
+ 300, 299, 298, 297, 296, 295, 294, 293, 292, 291,
+ 288, 286, 285, 284, 283, 282, 281, 280, 279, 277,
+ 273, 271, 270, 269, 268, 264, 263, 262, 261, 260,
+
+ 259, 258, 257, 256, 252, 250, 249, 248, 241, 240,
+ 239, 238, 236, 235, 234, 233, 232, 230, 229, 228,
+ 227, 226, 225, 224, 223, 222, 221, 220, 219, 218,
+ 217, 216, 215, 213, 212, 211, 210, 209, 208, 207,
+ 206, 205, 204, 203, 201, 200, 199, 198, 197, 196,
+ 195, 194, 193, 192, 191, 190, 189, 188, 187, 186,
+ 185, 183, 182, 181, 180, 179, 178, 177, 176, 175,
+ 174, 173, 172, 170, 169, 168, 167, 165, 164, 163,
+ 162, 161, 159, 145, 144, 142, 141, 140, 136, 135,
+ 134, 133, 132, 129, 128, 127, 126, 124, 123, 121,
+
+ 119, 118, 117, 115, 114, 113, 111, 110, 108, 107,
+ 106, 105, 104, 103, 100, 99, 98, 97, 96, 95,
+ 94, 93, 91, 90, 89, 88, 87, 86, 84, 83,
+ 79, 75, 44, 42, 36, 23, 20, 17, 12, 7,
+ 3, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 812, 812, 812, 812
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[238] =
+ { 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/*
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+#include "compiler/translator/glslang.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/length_limits.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION \
+ yylloc->first_file = yylloc->last_file = yycolumn; \
+ yylloc->first_line = yylloc->last_line = yylineno;
+
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
+static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
+static int ES2_ident_ES3_keyword(TParseContext *context, int token);
+static int uint_constant(TParseContext *context);
+static int int_constant(yyscan_t yyscanner);
+static int float_constant(yyscan_t yyscanner);
+static int floatsuffix_check(TParseContext* context);
+
+#define INITIAL 0
+
+#define YY_EXTRA_TYPE TParseContext*
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ yy_size_t yy_n_chars;
+ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ YYLTYPE * yylloc_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+ # define yylloc yyg->yylloc_r
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (yyscan_t yyscanner );
+
+int yyget_debug (yyscan_t yyscanner );
+
+void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *yyget_in (yyscan_t yyscanner );
+
+void yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *yyget_out (yyscan_t yyscanner );
+
+void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t yyget_leng (yyscan_t yyscanner );
+
+char *yyget_text (yyscan_t yyscanner );
+
+int yyget_lineno (yyscan_t yyscanner );
+
+void yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+int yyget_column (yyscan_t yyscanner );
+
+void yyset_column (int column_no ,yyscan_t yyscanner );
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner );
+
+void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+ YYLTYPE *yyget_lloc (yyscan_t yyscanner );
+
+ void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (yyscan_t yyscanner );
+#else
+extern int yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex \
+ (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ TParseContext* context = yyextra;
+
+ yylval = yylval_param;
+
+ yylloc = yylloc_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 813 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 812 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{ return INVARIANT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ return HIGH_PRECISION; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ return MEDIUM_PRECISION; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ return LOW_PRECISION; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ return PRECISION; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return ES2_keyword_ES3_reserved(context, ATTRIBUTE); }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return CONST_QUAL; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return UNIFORM; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return ES2_keyword_ES3_reserved(context, VARYING); }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return BREAK; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return CONTINUE; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return DO; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return FOR; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return WHILE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return IF; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return ELSE; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SWITCH); }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CASE); }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, DEFAULT); }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, CENTROID); }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, FLAT); }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SMOOTH); }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return IN_QUAL; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ return OUT_QUAL; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ return INOUT_QUAL; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ return FLOAT_TYPE; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ return INT_TYPE; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UINT_TYPE); }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ return VOID_TYPE; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ return BOOL_TYPE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ yylval->lex.b = true; return BOOLCONSTANT; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ yylval->lex.b = false; return BOOLCONSTANT; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ return DISCARD; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ return RETURN; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ return MATRIX2; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ return MATRIX3; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ return MATRIX4; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2); }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3); }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4); }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x3); }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x2); }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX2x4); }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x2); }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX3x4); }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, MATRIX4x3); }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ return VEC2; }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return VEC3; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return VEC4; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ return IVEC2; }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ return IVEC3; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ return IVEC4; }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return BVEC2; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ return BVEC3; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ return BVEC4; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC2); }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC3); }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, UVEC4); }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ return SAMPLER2D; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ return SAMPLERCUBE; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ return SAMPLER_EXTERNAL_OES; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3D); }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ return SAMPLER2DRECT; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2D); }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER3D); }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2D); }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER3D); }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLERCUBE); }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ return STRUCT; }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ return ES2_ident_ES3_keyword(context, LAYOUT); }
+ YY_BREAK
+/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
+case 79:
+case 80:
+case 81:
+case 82:
+case 83:
+case 84:
+case 85:
+case 86:
+case 87:
+case 88:
+case 89:
+case 90:
+case 91:
+case 92:
+case 93:
+case 94:
+case 95:
+case 96:
+case 97:
+case 98:
+case 99:
+case 100:
+case 101:
+case 102:
+case 103:
+case 104:
+case 105:
+case 106:
+case 107:
+case 108:
+case 109:
+case 110:
+case 111:
+case 112:
+case 113:
+case 114:
+case 115:
+case 116:
+case 117:
+case 118:
+case 119:
+case 120:
+case 121:
+case 122:
+case 123:
+case 124:
+case 125:
+case 126:
+case 127:
+case 128:
+case 129:
+case 130:
+case 131:
+case 132:
+case 133:
+case 134:
+YY_RULE_SETUP
+{
+ if (context->shaderVersion < 300) {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+ return reserved_word(yyscanner);
+}
+ YY_BREAK
+/* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
+case 135:
+YY_RULE_SETUP
+{
+ if (context->shaderVersion >= 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return reserved_word(yyscanner);
+}
+ YY_BREAK
+/* Reserved keywords */
+case 136:
+case 137:
+case 138:
+case 139:
+case 140:
+case 141:
+case 142:
+case 143:
+case 144:
+case 145:
+case 146:
+case 147:
+case 148:
+case 149:
+case 150:
+case 151:
+case 152:
+case 153:
+case 154:
+case 155:
+case 156:
+case 157:
+case 158:
+case 159:
+case 160:
+case 161:
+case 162:
+case 163:
+case 164:
+case 165:
+case 166:
+case 167:
+case 168:
+case 169:
+case 170:
+case 171:
+case 172:
+case 173:
+case 174:
+case 175:
+case 176:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 177:
+YY_RULE_SETUP
+{
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+ YY_BREAK
+case 178:
+YY_RULE_SETUP
+{ return int_constant(yyscanner); }
+ YY_BREAK
+case 179:
+YY_RULE_SETUP
+{ return int_constant(yyscanner); }
+ YY_BREAK
+case 180:
+YY_RULE_SETUP
+{ return int_constant(yyscanner); }
+ YY_BREAK
+case 181:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 182:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 183:
+YY_RULE_SETUP
+{ return uint_constant(context); }
+ YY_BREAK
+case 184:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 185:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 186:
+YY_RULE_SETUP
+{ return float_constant(yyscanner); }
+ YY_BREAK
+case 187:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 188:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 189:
+YY_RULE_SETUP
+{ return floatsuffix_check(context); }
+ YY_BREAK
+case 190:
+YY_RULE_SETUP
+{ return ADD_ASSIGN; }
+ YY_BREAK
+case 191:
+YY_RULE_SETUP
+{ return SUB_ASSIGN; }
+ YY_BREAK
+case 192:
+YY_RULE_SETUP
+{ return MUL_ASSIGN; }
+ YY_BREAK
+case 193:
+YY_RULE_SETUP
+{ return DIV_ASSIGN; }
+ YY_BREAK
+case 194:
+YY_RULE_SETUP
+{ return MOD_ASSIGN; }
+ YY_BREAK
+case 195:
+YY_RULE_SETUP
+{ return LEFT_ASSIGN; }
+ YY_BREAK
+case 196:
+YY_RULE_SETUP
+{ return RIGHT_ASSIGN; }
+ YY_BREAK
+case 197:
+YY_RULE_SETUP
+{ return AND_ASSIGN; }
+ YY_BREAK
+case 198:
+YY_RULE_SETUP
+{ return XOR_ASSIGN; }
+ YY_BREAK
+case 199:
+YY_RULE_SETUP
+{ return OR_ASSIGN; }
+ YY_BREAK
+case 200:
+YY_RULE_SETUP
+{ return INC_OP; }
+ YY_BREAK
+case 201:
+YY_RULE_SETUP
+{ return DEC_OP; }
+ YY_BREAK
+case 202:
+YY_RULE_SETUP
+{ return AND_OP; }
+ YY_BREAK
+case 203:
+YY_RULE_SETUP
+{ return OR_OP; }
+ YY_BREAK
+case 204:
+YY_RULE_SETUP
+{ return XOR_OP; }
+ YY_BREAK
+case 205:
+YY_RULE_SETUP
+{ return LE_OP; }
+ YY_BREAK
+case 206:
+YY_RULE_SETUP
+{ return GE_OP; }
+ YY_BREAK
+case 207:
+YY_RULE_SETUP
+{ return EQ_OP; }
+ YY_BREAK
+case 208:
+YY_RULE_SETUP
+{ return NE_OP; }
+ YY_BREAK
+case 209:
+YY_RULE_SETUP
+{ return LEFT_OP; }
+ YY_BREAK
+case 210:
+YY_RULE_SETUP
+{ return RIGHT_OP; }
+ YY_BREAK
+case 211:
+YY_RULE_SETUP
+{ return SEMICOLON; }
+ YY_BREAK
+case 212:
+YY_RULE_SETUP
+{ return LEFT_BRACE; }
+ YY_BREAK
+case 213:
+YY_RULE_SETUP
+{ return RIGHT_BRACE; }
+ YY_BREAK
+case 214:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 215:
+YY_RULE_SETUP
+{ return COLON; }
+ YY_BREAK
+case 216:
+YY_RULE_SETUP
+{ return EQUAL; }
+ YY_BREAK
+case 217:
+YY_RULE_SETUP
+{ return LEFT_PAREN; }
+ YY_BREAK
+case 218:
+YY_RULE_SETUP
+{ return RIGHT_PAREN; }
+ YY_BREAK
+case 219:
+YY_RULE_SETUP
+{ return LEFT_BRACKET; }
+ YY_BREAK
+case 220:
+YY_RULE_SETUP
+{ return RIGHT_BRACKET; }
+ YY_BREAK
+case 221:
+YY_RULE_SETUP
+{ return DOT; }
+ YY_BREAK
+case 222:
+YY_RULE_SETUP
+{ return BANG; }
+ YY_BREAK
+case 223:
+YY_RULE_SETUP
+{ return DASH; }
+ YY_BREAK
+case 224:
+YY_RULE_SETUP
+{ return TILDE; }
+ YY_BREAK
+case 225:
+YY_RULE_SETUP
+{ return PLUS; }
+ YY_BREAK
+case 226:
+YY_RULE_SETUP
+{ return STAR; }
+ YY_BREAK
+case 227:
+YY_RULE_SETUP
+{ return SLASH; }
+ YY_BREAK
+case 228:
+YY_RULE_SETUP
+{ return PERCENT; }
+ YY_BREAK
+case 229:
+YY_RULE_SETUP
+{ return LEFT_ANGLE; }
+ YY_BREAK
+case 230:
+YY_RULE_SETUP
+{ return RIGHT_ANGLE; }
+ YY_BREAK
+case 231:
+YY_RULE_SETUP
+{ return VERTICAL_BAR; }
+ YY_BREAK
+case 232:
+YY_RULE_SETUP
+{ return CARET; }
+ YY_BREAK
+case 233:
+YY_RULE_SETUP
+{ return AMPERSAND; }
+ YY_BREAK
+case 234:
+YY_RULE_SETUP
+{ return QUESTION; }
+ YY_BREAK
+case 235:
+/* rule 235 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+{ yyterminate(); }
+ YY_BREAK
+case 236:
+YY_RULE_SETUP
+{ assert(false); return 0; }
+ YY_BREAK
+case 237:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 813 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 813 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 812);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+YYLTYPE *yyget_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+
+int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ pp::Token token;
+ yyget_extra(yyscanner)->preprocessor.lex(&token);
+ yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
+ if (len < max_size)
+ memcpy(buf, token.text.c_str(), len);
+ yyset_column(token.location.file,yyscanner);
+ yyset_lineno(token.location.line,yyscanner);
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion);
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ token = TYPE_NAME;
+ }
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(*yylloc, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+int ES2_reserved_ES3_keyword(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_keyword_ES3_reserved(TParseContext *context, int token)
+{
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion >= 300)
+ {
+ return reserved_word(yyscanner);
+ }
+
+ return token;
+}
+
+int ES2_ident_ES3_keyword(TParseContext *context, int token)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name
+ if (context->shaderVersion < 300)
+ {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+ }
+
+ return token;
+}
+
+int uint_constant(TParseContext *context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
+ context->recover();
+ return 0;
+ }
+
+ if (!atoi_clamp(yytext, &(yylval->lex.i)))
+ yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+
+ return UINTCONSTANT;
+}
+
+int floatsuffix_check(TParseContext* context)
+{
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+ if (context->shaderVersion < 300)
+ {
+ context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
+ context->recover();
+ return 0;
+ }
+
+ if (!atof_clamp(yytext, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext, "");
+
+ return(FLOATCONSTANT);
+}
+
+void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) {
+ context->error(*lloc, reason, yyget_text(context->scanner));
+ context->recover();
+}
+
+int int_constant(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ if (!atoi_clamp(yytext, &(yylval->lex.i)))
+ yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+ return INTCONSTANT;
+}
+
+int float_constant(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ if (!atof_clamp(yytext, &(yylval->lex.f)))
+ yyextra->warning(*yylloc, "Float overflow", yytext, "");
+ return FLOATCONSTANT;
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context,&scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ yylex_destroy(scanner);
+
+ return 0;
+}
+
+int glslang_scan(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL,context->scanner);
+ yyset_column(0,context->scanner);
+ yyset_lineno(1,context->scanner);
+
+ // Initialize preprocessor.
+ if (!context->preprocessor.init(count, string, length))
+ return 1;
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+ }
+ if (context->fragmentPrecisionHigh)
+ context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec));
+
+ return 0;
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp
new file mode 100644
index 00000000000..63ec8c7534f
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp
@@ -0,0 +1,5263 @@
+/* A Bison parser, made by GNU Bison 2.7.1. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+
+
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/ParseContext.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+#define YYLEX_PARAM context->scanner
+
+
+
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "glslang_tab.h". */
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ UINT_TYPE = 268,
+ BREAK = 269,
+ CONTINUE = 270,
+ DO = 271,
+ ELSE = 272,
+ FOR = 273,
+ IF = 274,
+ DISCARD = 275,
+ RETURN = 276,
+ SWITCH = 277,
+ CASE = 278,
+ DEFAULT = 279,
+ BVEC2 = 280,
+ BVEC3 = 281,
+ BVEC4 = 282,
+ IVEC2 = 283,
+ IVEC3 = 284,
+ IVEC4 = 285,
+ VEC2 = 286,
+ VEC3 = 287,
+ VEC4 = 288,
+ UVEC2 = 289,
+ UVEC3 = 290,
+ UVEC4 = 291,
+ MATRIX2 = 292,
+ MATRIX3 = 293,
+ MATRIX4 = 294,
+ IN_QUAL = 295,
+ OUT_QUAL = 296,
+ INOUT_QUAL = 297,
+ UNIFORM = 298,
+ VARYING = 299,
+ MATRIX2x3 = 300,
+ MATRIX3x2 = 301,
+ MATRIX2x4 = 302,
+ MATRIX4x2 = 303,
+ MATRIX3x4 = 304,
+ MATRIX4x3 = 305,
+ CENTROID = 306,
+ FLAT = 307,
+ SMOOTH = 308,
+ STRUCT = 309,
+ VOID_TYPE = 310,
+ WHILE = 311,
+ SAMPLER2D = 312,
+ SAMPLERCUBE = 313,
+ SAMPLER_EXTERNAL_OES = 314,
+ SAMPLER2DRECT = 315,
+ SAMPLER2DARRAY = 316,
+ ISAMPLER2D = 317,
+ ISAMPLER3D = 318,
+ ISAMPLERCUBE = 319,
+ ISAMPLER2DARRAY = 320,
+ USAMPLER2D = 321,
+ USAMPLER3D = 322,
+ USAMPLERCUBE = 323,
+ USAMPLER2DARRAY = 324,
+ SAMPLER3D = 325,
+ SAMPLER3DRECT = 326,
+ SAMPLER2DSHADOW = 327,
+ SAMPLERCUBESHADOW = 328,
+ SAMPLER2DARRAYSHADOW = 329,
+ LAYOUT = 330,
+ IDENTIFIER = 331,
+ TYPE_NAME = 332,
+ FLOATCONSTANT = 333,
+ INTCONSTANT = 334,
+ UINTCONSTANT = 335,
+ BOOLCONSTANT = 336,
+ FIELD_SELECTION = 337,
+ LEFT_OP = 338,
+ RIGHT_OP = 339,
+ INC_OP = 340,
+ DEC_OP = 341,
+ LE_OP = 342,
+ GE_OP = 343,
+ EQ_OP = 344,
+ NE_OP = 345,
+ AND_OP = 346,
+ OR_OP = 347,
+ XOR_OP = 348,
+ MUL_ASSIGN = 349,
+ DIV_ASSIGN = 350,
+ ADD_ASSIGN = 351,
+ MOD_ASSIGN = 352,
+ LEFT_ASSIGN = 353,
+ RIGHT_ASSIGN = 354,
+ AND_ASSIGN = 355,
+ XOR_ASSIGN = 356,
+ OR_ASSIGN = 357,
+ SUB_ASSIGN = 358,
+ LEFT_PAREN = 359,
+ RIGHT_PAREN = 360,
+ LEFT_BRACKET = 361,
+ RIGHT_BRACKET = 362,
+ LEFT_BRACE = 363,
+ RIGHT_BRACE = 364,
+ DOT = 365,
+ COMMA = 366,
+ COLON = 367,
+ EQUAL = 368,
+ SEMICOLON = 369,
+ BANG = 370,
+ DASH = 371,
+ TILDE = 372,
+ PLUS = 373,
+ STAR = 374,
+ SLASH = 375,
+ PERCENT = 376,
+ LEFT_ANGLE = 377,
+ RIGHT_ANGLE = 378,
+ VERTICAL_BAR = 379,
+ CARET = 380,
+ AMPERSAND = 381,
+ QUESTION = 382
+ };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (TParseContext* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+
+extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
+extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason);
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ } \
+ else { \
+ (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \
+ } \
+ } while (0)
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define ES2_ONLY(S, L) { \
+ if (context->shaderVersion != 100) { \
+ context->error(L, " supported in GLSL ES 1.00 only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define ES3_ONLY(TOKEN, LINE, REASON) { \
+ if (context->shaderVersion != 300) { \
+ context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \
+ context->recover(); \
+ } \
+}
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 114
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2375
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 128
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 91
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 250
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 373
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 382
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 13, 15, 17,
+ 19, 23, 25, 30, 32, 36, 39, 42, 44, 46,
+ 48, 52, 55, 58, 61, 63, 66, 70, 73, 75,
+ 77, 79, 82, 85, 88, 90, 92, 94, 96, 100,
+ 104, 106, 110, 114, 116, 118, 122, 126, 130, 134,
+ 136, 140, 144, 146, 148, 150, 152, 156, 158, 162,
+ 164, 168, 170, 176, 178, 182, 184, 186, 188, 190,
+ 192, 194, 198, 200, 203, 206, 209, 214, 220, 227,
+ 237, 240, 243, 245, 247, 250, 254, 258, 261, 267,
+ 271, 274, 278, 281, 282, 284, 286, 288, 290, 292,
+ 296, 302, 309, 315, 317, 320, 325, 331, 336, 339,
+ 341, 344, 346, 348, 350, 352, 354, 357, 359, 362,
+ 364, 366, 369, 371, 373, 375, 378, 381, 383, 385,
+ 388, 390, 392, 394, 399, 401, 405, 407, 411, 415,
+ 417, 422, 424, 426, 428, 430, 432, 434, 436, 438,
+ 440, 442, 444, 446, 448, 450, 452, 454, 456, 458,
+ 460, 462, 464, 466, 468, 470, 472, 474, 476, 478,
+ 480, 482, 484, 486, 488, 490, 492, 494, 496, 498,
+ 500, 502, 504, 506, 508, 510, 512, 513, 520, 521,
+ 527, 529, 532, 536, 541, 543, 547, 549, 554, 556,
+ 558, 560, 562, 564, 566, 568, 570, 572, 575, 576,
+ 577, 583, 585, 587, 588, 591, 592, 595, 598, 602,
+ 604, 607, 609, 612, 618, 622, 624, 626, 631, 632,
+ 639, 640, 649, 650, 658, 660, 662, 664, 665, 668,
+ 672, 675, 678, 681, 685, 688, 690, 693, 695, 697,
+ 698
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 215, 0, -1, 76, -1, 77, -1, 76, -1, 130,
+ -1, 79, -1, 80, -1, 78, -1, 81, -1, 104,
+ 157, 105, -1, 131, -1, 132, 106, 133, 107, -1,
+ 134, -1, 132, 110, 129, -1, 132, 85, -1, 132,
+ 86, -1, 157, -1, 135, -1, 136, -1, 132, 110,
+ 136, -1, 138, 105, -1, 137, 105, -1, 139, 55,
+ -1, 139, -1, 139, 155, -1, 138, 111, 155, -1,
+ 140, 104, -1, 182, -1, 76, -1, 132, -1, 85,
+ 141, -1, 86, 141, -1, 142, 141, -1, 118, -1,
+ 116, -1, 115, -1, 141, -1, 143, 119, 141, -1,
+ 143, 120, 141, -1, 143, -1, 144, 118, 143, -1,
+ 144, 116, 143, -1, 144, -1, 145, -1, 146, 122,
+ 145, -1, 146, 123, 145, -1, 146, 87, 145, -1,
+ 146, 88, 145, -1, 146, -1, 147, 89, 146, -1,
+ 147, 90, 146, -1, 147, -1, 148, -1, 149, -1,
+ 150, -1, 151, 91, 150, -1, 151, -1, 152, 93,
+ 151, -1, 152, -1, 153, 92, 152, -1, 153, -1,
+ 153, 127, 157, 112, 155, -1, 154, -1, 141, 156,
+ 155, -1, 113, -1, 94, -1, 95, -1, 96, -1,
+ 103, -1, 155, -1, 157, 111, 155, -1, 154, -1,
+ 76, 108, -1, 161, 114, -1, 169, 114, -1, 7,
+ 177, 181, 114, -1, 174, 159, 186, 109, 114, -1,
+ 174, 159, 186, 109, 76, 114, -1, 174, 159, 186,
+ 109, 76, 106, 158, 107, 114, -1, 174, 114, -1,
+ 162, 105, -1, 164, -1, 163, -1, 164, 166, -1,
+ 163, 111, 166, -1, 171, 76, 104, -1, 176, 129,
+ -1, 176, 129, 106, 158, 107, -1, 173, 167, 165,
+ -1, 167, 165, -1, 173, 167, 168, -1, 167, 168,
+ -1, -1, 40, -1, 41, -1, 42, -1, 176, -1,
+ 170, -1, 169, 111, 129, -1, 169, 111, 129, 106,
+ 107, -1, 169, 111, 129, 106, 158, 107, -1, 169,
+ 111, 129, 113, 190, -1, 171, -1, 171, 129, -1,
+ 171, 129, 106, 107, -1, 171, 129, 106, 158, 107,
+ -1, 171, 129, 113, 190, -1, 3, 76, -1, 176,
+ -1, 174, 176, -1, 53, -1, 52, -1, 9, -1,
+ 8, -1, 44, -1, 3, 44, -1, 175, -1, 172,
+ 175, -1, 172, -1, 178, -1, 178, 175, -1, 9,
+ -1, 40, -1, 41, -1, 51, 40, -1, 51, 41,
+ -1, 43, -1, 181, -1, 177, 181, -1, 4, -1,
+ 5, -1, 6, -1, 75, 104, 179, 105, -1, 180,
+ -1, 179, 111, 180, -1, 76, -1, 76, 113, 79,
+ -1, 76, 113, 80, -1, 182, -1, 182, 106, 158,
+ 107, -1, 55, -1, 11, -1, 12, -1, 13, -1,
+ 10, -1, 31, -1, 32, -1, 33, -1, 25, -1,
+ 26, -1, 27, -1, 28, -1, 29, -1, 30, -1,
+ 34, -1, 35, -1, 36, -1, 37, -1, 38, -1,
+ 39, -1, 45, -1, 46, -1, 47, -1, 48, -1,
+ 49, -1, 50, -1, 57, -1, 70, -1, 58, -1,
+ 61, -1, 62, -1, 63, -1, 64, -1, 65, -1,
+ 66, -1, 67, -1, 68, -1, 69, -1, 72, -1,
+ 73, -1, 74, -1, 59, -1, 60, -1, 183, -1,
+ 77, -1, -1, 54, 129, 108, 184, 186, 109, -1,
+ -1, 54, 108, 185, 186, 109, -1, 187, -1, 186,
+ 187, -1, 176, 188, 114, -1, 174, 176, 188, 114,
+ -1, 189, -1, 188, 111, 189, -1, 129, -1, 129,
+ 106, 158, 107, -1, 155, -1, 160, -1, 194, -1,
+ 193, -1, 191, -1, 203, -1, 204, -1, 207, -1,
+ 214, -1, 108, 109, -1, -1, -1, 108, 195, 202,
+ 196, 109, -1, 201, -1, 193, -1, -1, 199, 201,
+ -1, -1, 200, 193, -1, 108, 109, -1, 108, 202,
+ 109, -1, 192, -1, 202, 192, -1, 114, -1, 157,
+ 114, -1, 19, 104, 157, 105, 205, -1, 198, 17,
+ 198, -1, 198, -1, 157, -1, 171, 129, 113, 190,
+ -1, -1, 56, 104, 208, 206, 105, 197, -1, -1,
+ 16, 209, 198, 56, 104, 157, 105, 114, -1, -1,
+ 18, 104, 210, 211, 213, 105, 197, -1, 203, -1,
+ 191, -1, 206, -1, -1, 212, 114, -1, 212, 114,
+ 157, -1, 15, 114, -1, 14, 114, -1, 21, 114,
+ -1, 21, 157, 114, -1, 20, 114, -1, 216, -1,
+ 215, 216, -1, 217, -1, 160, -1, -1, 161, 218,
+ 201, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 205, 205, 206, 209, 264, 267, 272, 277, 282,
+ 287, 293, 296, 299, 302, 305, 315, 328, 336, 436,
+ 439, 447, 450, 456, 460, 467, 473, 482, 490, 493,
+ 503, 506, 516, 526, 547, 548, 549, 554, 555, 563,
+ 574, 575, 583, 594, 598, 599, 609, 619, 629, 642,
+ 643, 653, 666, 670, 674, 678, 679, 692, 693, 706,
+ 707, 720, 721, 738, 739, 752, 753, 754, 755, 756,
+ 760, 763, 774, 782, 790, 817, 822, 833, 837, 841,
+ 845, 852, 907, 910, 917, 925, 946, 967, 977, 1005,
+ 1010, 1020, 1025, 1035, 1038, 1041, 1044, 1050, 1057, 1060,
+ 1064, 1068, 1072, 1079, 1083, 1087, 1094, 1098, 1102, 1123,
+ 1132, 1138, 1141, 1147, 1153, 1160, 1169, 1178, 1186, 1189,
+ 1196, 1200, 1207, 1210, 1214, 1218, 1227, 1236, 1244, 1254,
+ 1266, 1269, 1272, 1278, 1285, 1288, 1294, 1297, 1300, 1306,
+ 1309, 1324, 1328, 1332, 1336, 1340, 1344, 1349, 1354, 1359,
+ 1364, 1369, 1374, 1379, 1384, 1389, 1394, 1399, 1404, 1409,
+ 1414, 1419, 1424, 1429, 1434, 1439, 1444, 1449, 1453, 1457,
+ 1461, 1465, 1469, 1473, 1477, 1481, 1485, 1489, 1493, 1497,
+ 1501, 1505, 1509, 1517, 1525, 1529, 1542, 1542, 1545, 1545,
+ 1551, 1554, 1570, 1573, 1582, 1586, 1592, 1599, 1614, 1618,
+ 1622, 1623, 1629, 1630, 1631, 1632, 1633, 1637, 1638, 1638,
+ 1638, 1648, 1649, 1653, 1653, 1654, 1654, 1659, 1662, 1672,
+ 1675, 1681, 1682, 1686, 1694, 1698, 1708, 1713, 1730, 1730,
+ 1735, 1735, 1742, 1742, 1750, 1753, 1759, 1762, 1768, 1772,
+ 1779, 1786, 1793, 1800, 1811, 1820, 1824, 1831, 1834, 1840,
+ 1840
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION",
+ "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE",
+ "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "UINT_TYPE",
+ "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN",
+ "SWITCH", "CASE", "DEFAULT", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3",
+ "IVEC4", "VEC2", "VEC3", "VEC4", "UVEC2", "UVEC3", "UVEC4", "MATRIX2",
+ "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM",
+ "VARYING", "MATRIX2x3", "MATRIX3x2", "MATRIX2x4", "MATRIX4x2",
+ "MATRIX3x4", "MATRIX4x3", "CENTROID", "FLAT", "SMOOTH", "STRUCT",
+ "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", "SAMPLER_EXTERNAL_OES",
+ "SAMPLER2DRECT", "SAMPLER2DARRAY", "ISAMPLER2D", "ISAMPLER3D",
+ "ISAMPLERCUBE", "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D",
+ "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER3D", "SAMPLER3DRECT",
+ "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", "SAMPLER2DARRAYSHADOW", "LAYOUT",
+ "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", "INTCONSTANT",
+ "UINTCONSTANT", "BOOLCONSTANT", "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP",
+ "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP",
+ "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN",
+ "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN",
+ "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET",
+ "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON",
+ "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH",
+ "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET",
+ "AMPERSAND", "QUESTION", "$accept", "identifier", "variable_identifier",
+ "primary_expression", "postfix_expression", "integer_expression",
+ "function_call", "function_call_or_method", "function_call_generic",
+ "function_call_header_no_parameters",
+ "function_call_header_with_parameters", "function_call_header",
+ "function_identifier", "unary_expression", "unary_operator",
+ "multiplicative_expression", "additive_expression", "shift_expression",
+ "relational_expression", "equality_expression", "and_expression",
+ "exclusive_or_expression", "inclusive_or_expression",
+ "logical_and_expression", "logical_xor_expression",
+ "logical_or_expression", "conditional_expression",
+ "assignment_expression", "assignment_operator", "expression",
+ "constant_expression", "enter_struct", "declaration",
+ "function_prototype", "function_declarator",
+ "function_header_with_parameters", "function_header",
+ "parameter_declarator", "parameter_declaration", "parameter_qualifier",
+ "parameter_type_specifier", "init_declarator_list", "single_declaration",
+ "fully_specified_type", "interpolation_qualifier",
+ "parameter_type_qualifier", "type_qualifier", "storage_qualifier",
+ "type_specifier", "precision_qualifier", "layout_qualifier",
+ "layout_qualifier_id_list", "layout_qualifier_id",
+ "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier",
+ "$@1", "$@2", "struct_declaration_list", "struct_declaration",
+ "struct_declarator_list", "struct_declarator", "initializer",
+ "declaration_statement", "statement", "simple_statement",
+ "compound_statement", "$@3", "$@4", "statement_no_new_scope",
+ "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope",
+ "statement_list", "expression_statement", "selection_statement",
+ "selection_rest_statement", "condition", "iteration_statement", "$@7",
+ "$@8", "$@9", "for_init_statement", "conditionopt", "for_rest_statement",
+ "jump_statement", "translation_unit", "external_declaration",
+ "function_definition", "$@10", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 128, 129, 129, 130, 131, 131, 131, 131, 131,
+ 131, 132, 132, 132, 132, 132, 132, 133, 134, 135,
+ 135, 136, 136, 137, 137, 138, 138, 139, 140, 140,
+ 141, 141, 141, 141, 142, 142, 142, 143, 143, 143,
+ 144, 144, 144, 145, 146, 146, 146, 146, 146, 147,
+ 147, 147, 148, 149, 150, 151, 151, 152, 152, 153,
+ 153, 154, 154, 155, 155, 156, 156, 156, 156, 156,
+ 157, 157, 158, 159, 160, 160, 160, 160, 160, 160,
+ 160, 161, 162, 162, 163, 163, 164, 165, 165, 166,
+ 166, 166, 166, 167, 167, 167, 167, 168, 169, 169,
+ 169, 169, 169, 170, 170, 170, 170, 170, 170, 171,
+ 171, 172, 172, 173, 174, 174, 174, 174, 174, 174,
+ 174, 174, 175, 175, 175, 175, 175, 175, 176, 176,
+ 177, 177, 177, 178, 179, 179, 180, 180, 180, 181,
+ 181, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 184, 183, 185, 183,
+ 186, 186, 187, 187, 188, 188, 189, 189, 190, 191,
+ 192, 192, 193, 193, 193, 193, 193, 194, 195, 196,
+ 194, 197, 197, 199, 198, 200, 198, 201, 201, 202,
+ 202, 203, 203, 204, 205, 205, 206, 206, 208, 207,
+ 209, 207, 210, 207, 211, 211, 212, 212, 213, 213,
+ 214, 214, 214, 214, 214, 215, 215, 216, 216, 218,
+ 217
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 1, 4, 1, 3, 2, 2, 1, 1, 1,
+ 3, 2, 2, 2, 1, 2, 3, 2, 1, 1,
+ 1, 2, 2, 2, 1, 1, 1, 1, 3, 3,
+ 1, 3, 3, 1, 1, 3, 3, 3, 3, 1,
+ 3, 3, 1, 1, 1, 1, 3, 1, 3, 1,
+ 3, 1, 5, 1, 3, 1, 1, 1, 1, 1,
+ 1, 3, 1, 2, 2, 2, 4, 5, 6, 9,
+ 2, 2, 1, 1, 2, 3, 3, 2, 5, 3,
+ 2, 3, 2, 0, 1, 1, 1, 1, 1, 3,
+ 5, 6, 5, 1, 2, 4, 5, 4, 2, 1,
+ 2, 1, 1, 1, 1, 1, 2, 1, 2, 1,
+ 1, 2, 1, 1, 1, 2, 2, 1, 1, 2,
+ 1, 1, 1, 4, 1, 3, 1, 3, 3, 1,
+ 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 6, 0, 5,
+ 1, 2, 3, 4, 1, 3, 1, 4, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 0, 0,
+ 5, 1, 1, 0, 2, 0, 2, 2, 3, 1,
+ 2, 1, 2, 5, 3, 1, 1, 4, 0, 6,
+ 0, 8, 0, 7, 1, 1, 1, 0, 2, 3,
+ 2, 2, 2, 3, 2, 1, 2, 1, 1, 0,
+ 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 130, 131, 132, 0, 114, 122, 145, 142,
+ 143, 144, 149, 150, 151, 152, 153, 154, 146, 147,
+ 148, 155, 156, 157, 158, 159, 160, 123, 124, 127,
+ 115, 161, 162, 163, 164, 165, 166, 0, 112, 111,
+ 0, 141, 167, 169, 182, 183, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 168, 179, 180, 181, 0,
+ 185, 248, 249, 0, 83, 93, 0, 98, 103, 119,
+ 0, 117, 109, 0, 120, 128, 139, 184, 0, 245,
+ 247, 116, 108, 0, 125, 126, 2, 3, 188, 0,
+ 0, 74, 0, 81, 93, 113, 94, 95, 96, 84,
+ 0, 93, 0, 75, 2, 104, 118, 0, 80, 0,
+ 110, 129, 121, 0, 1, 246, 0, 0, 186, 136,
+ 0, 134, 0, 250, 85, 90, 92, 97, 0, 99,
+ 86, 0, 0, 73, 0, 0, 0, 0, 190, 4,
+ 8, 6, 7, 9, 0, 0, 0, 36, 35, 34,
+ 5, 11, 30, 13, 18, 19, 0, 0, 24, 0,
+ 37, 0, 40, 43, 44, 49, 52, 53, 54, 55,
+ 57, 59, 61, 72, 0, 28, 76, 0, 0, 0,
+ 133, 0, 0, 0, 230, 0, 0, 0, 0, 0,
+ 208, 217, 221, 37, 63, 70, 0, 199, 0, 139,
+ 202, 219, 201, 200, 0, 203, 204, 205, 206, 87,
+ 89, 91, 0, 0, 105, 0, 198, 107, 0, 196,
+ 0, 194, 0, 191, 31, 32, 0, 15, 16, 0,
+ 0, 22, 21, 0, 23, 25, 27, 33, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 140, 189, 0, 137, 138, 135, 241, 240,
+ 215, 232, 0, 244, 242, 0, 228, 207, 0, 66,
+ 67, 68, 69, 65, 0, 0, 222, 218, 220, 0,
+ 100, 0, 102, 106, 0, 0, 0, 192, 0, 77,
+ 10, 0, 17, 2, 3, 14, 20, 26, 38, 39,
+ 42, 41, 47, 48, 45, 46, 50, 51, 56, 58,
+ 60, 0, 187, 0, 0, 0, 0, 0, 243, 0,
+ 209, 64, 71, 0, 101, 193, 0, 195, 0, 78,
+ 12, 0, 0, 214, 216, 235, 234, 237, 215, 226,
+ 0, 0, 0, 0, 88, 197, 0, 62, 0, 236,
+ 0, 0, 225, 223, 0, 0, 210, 0, 0, 238,
+ 0, 215, 0, 212, 229, 211, 79, 0, 239, 233,
+ 224, 227, 231
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 219, 150, 151, 152, 291, 153, 154, 155, 156,
+ 157, 158, 159, 193, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 194, 195, 274, 196,
+ 174, 109, 197, 198, 63, 64, 65, 125, 99, 100,
+ 126, 66, 67, 68, 69, 101, 70, 71, 72, 73,
+ 74, 120, 121, 75, 175, 77, 178, 117, 137, 138,
+ 220, 221, 217, 200, 201, 202, 203, 268, 343, 364,
+ 313, 314, 315, 365, 204, 205, 206, 353, 342, 207,
+ 319, 260, 316, 337, 350, 351, 208, 78, 79, 80,
+ 92
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -309
+static const yytype_int16 yypact[] =
+{
+ 2013, -27, -309, -309, -309, 154, -309, -309, -309, -309,
+ -309, -309, -309, -309, -309, -309, -309, -309, -309, -309,
+ -309, -309, -309, -309, -309, -309, -309, -309, -309, -309,
+ -309, -309, -309, -309, -309, -309, -309, 98, -309, -309,
+ -40, -309, -309, -309, -309, -309, -309, -309, -309, -309,
+ -309, -309, -309, -309, -309, -309, -309, -309, -309, -46,
+ -309, -309, -42, -23, 8, 5, -87, -309, 91, 14,
+ 1130, -309, -309, 2298, 14, -309, -1, -309, 1938, -309,
+ -309, -309, -309, 2298, -309, -309, -309, -309, -309, 13,
+ 47, -309, 43, -309, 39, -309, -309, -309, -309, -309,
+ 2162, 124, 94, -309, 51, -14, -309, 66, -309, 2088,
+ -309, -309, -309, 1491, -309, -309, 62, 2088, -309, 48,
+ -83, -309, 358, -309, -309, -309, -309, 94, 2162, -9,
+ -309, 1200, 1491, -309, 148, 2162, 94, 1683, -309, 89,
+ -309, -309, -309, -309, 1491, 1491, 1491, -309, -309, -309,
+ -309, -309, 10, -309, -309, -309, 92, 20, 1586, 96,
+ -309, 1491, 53, -76, -309, -62, 90, -309, -309, -309,
+ 104, 101, -61, -309, 95, -309, -309, 1768, 2088, 103,
+ -309, 47, 82, 84, -309, 97, 99, 93, 1298, 105,
+ 102, -309, -309, -10, -309, -309, -13, -309, -42, 2,
+ -309, -309, -309, -309, 474, -309, -309, -309, -309, 106,
+ -309, -309, 1393, 1491, -309, 107, -309, -309, 94, 109,
+ 4, -309, -58, -309, -309, -309, 22, -309, -309, 1491,
+ 2230, -309, -309, 1491, 112, -309, -309, -309, 1491, 1491,
+ 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491,
+ 1491, 1491, -309, -309, 1853, -309, -309, -309, -309, -309,
+ 100, -309, 1491, -309, -309, 36, -309, -309, 590, -309,
+ -309, -309, -309, -309, 1491, 1491, -309, -309, -309, 1491,
+ -309, 113, -309, -309, 42, 1491, 94, -309, -73, -309,
+ -309, 115, 108, 89, 119, -309, -309, -309, -309, -309,
+ 53, 53, -309, -309, -309, -309, -62, -62, -309, 104,
+ 101, 73, -309, 169, 43, 822, 938, 25, -309, 1035,
+ 590, -309, -309, 120, -309, -309, 121, -309, 1491, -309,
+ -309, 1491, 122, -309, -309, -309, -309, 1035, 100, 108,
+ 94, 2162, 125, 123, -309, -309, 126, -309, 1491, -309,
+ 117, 129, 212, -309, 139, 706, -309, 141, 29, 1491,
+ 706, 100, 1491, -309, -309, -309, -309, 142, 108, -309,
+ -309, -309, -309
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -309, -39, -309, -309, -309, -309, -309, -309, 7, -309,
+ -309, -309, -309, 1, -309, -54, -309, -101, -57, -309,
+ -309, -309, 9, -11, 3, -309, -110, -126, -309, -138,
+ -122, -309, 11, 16, -309, -309, -309, 130, 165, 159,
+ 133, -309, -309, -299, -309, -309, -102, -30, -66, 257,
+ -309, -309, 83, -6, 0, -309, -309, -309, -104, -125,
+ 45, -21, -208, -50, -194, -296, -309, -309, -309, -93,
+ -308, -309, -309, -90, 6, -47, -309, -309, -67, -309,
+ -309, -309, -309, -309, -309, -309, -309, -309, 193, -309,
+ -309
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -214
+static const yytype_int16 yytable[] =
+{
+ 76, 89, 123, 173, 110, 282, 216, 135, 226, 215,
+ 278, 61, 223, 177, 95, 135, 62, 81, 288, 334,
+ 340, 173, 180, 7, 102, 242, 243, 103, 181, 105,
+ 352, 250, 235, 328, 127, 135, 86, 87, 340, 106,
+ 240, 329, 241, 136, 112, 96, 97, 98, 95, 82,
+ 265, 136, 223, 370, 27, 28, 289, 29, 90, 363,
+ 244, 245, 127, 129, 363, 37, 251, 111, 88, 218,
+ 76, 136, 91, 76, 254, 135, 135, 116, 76, 96,
+ 97, 98, 93, 76, 269, 270, 271, 216, 209, 61,
+ 281, 292, 131, 272, 62, 227, 228, 212, 275, 132,
+ 76, 276, 173, 273, 213, 113, -28, 297, 113, 76,
+ -82, 136, 136, 311, 160, 286, 229, 76, 287, 94,
+ 230, 118, 199, 119, 317, 232, 278, 290, 76, 223,
+ 338, 233, 160, 275, 367, 76, 275, 76, 84, 85,
+ 275, 302, 303, 304, 305, 224, 225, 275, 321, 322,
+ 318, 122, 135, 286, 371, 130, 325, 323, 2, 3,
+ 4, 179, 237, 326, 96, 97, 98, 104, 87, 173,
+ 86, 87, 238, 239, 133, 173, 176, 76, 76, 246,
+ 247, 339, 255, 256, 275, 331, 300, 301, 136, 306,
+ 307, 295, 81, -29, 249, 248, 258, 231, 259, 339,
+ 236, 261, 252, 262, 199, 347, 346, 263, -213, 266,
+ 358, 267, 279, 160, 283, 285, -141, 341, 173, 275,
+ 324, 368, 330, -185, 333, 332, 348, 344, 345, 361,
+ 355, 359, 356, 357, 360, 341, 216, 296, 309, 298,
+ 299, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 362, 310, 76, 366, 372, 308, 210, 124,
+ 128, 211, 83, 284, 257, 327, 335, 369, 199, 336,
+ 349, 115, 0, 0, 320, 110, 0, 0, 0, 0,
+ 160, 0, 0, 0, 0, 0, 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 354, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 199, 199, 0, 0, 199,
+ 199, 0, 0, 0, 0, 0, 0, 0, 0, 160,
+ 0, 0, 0, 0, 0, 0, 0, 199, 0, 0,
+ 0, 76, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 199, 0, 0, 0, 0,
+ 199, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 182, 183, 184, 0, 185, 186, 187, 188,
+ 0, 0, 0, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 189, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 59, 139, 60, 140, 141, 142, 143,
+ 0, 0, 0, 144, 145, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 146, 0, 0, 0, 190, 191, 0, 0,
+ 0, 0, 192, 147, 148, 0, 149, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 182, 183,
+ 184, 0, 185, 186, 187, 188, 0, 0, 0, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 0, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 189, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 0, 56, 57, 58, 59,
+ 139, 60, 140, 141, 142, 143, 0, 0, 0, 144,
+ 145, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 146, 0,
+ 0, 0, 190, 277, 0, 0, 0, 0, 192, 147,
+ 148, 0, 149, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 182, 183, 184, 0, 185, 186,
+ 187, 188, 0, 0, 0, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 0, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 189, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 0, 56, 57, 58, 59, 139, 60, 140, 141,
+ 142, 143, 0, 0, 0, 144, 145, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 146, 0, 0, 0, 190, 0,
+ 0, 0, 0, 0, 192, 147, 148, 0, 149, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 182, 183, 184, 0, 185, 186, 187, 188, 0, 0,
+ 0, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 0, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 189, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 0, 56, 57,
+ 58, 59, 139, 60, 140, 141, 142, 143, 0, 0,
+ 0, 144, 145, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 146, 0, 0, 0, 122, 0, 0, 0, 0, 0,
+ 192, 147, 148, 0, 149, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 182, 183, 184, 0,
+ 185, 186, 187, 188, 0, 0, 0, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 0, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 189, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 0, 56, 57, 58, 59, 139, 60,
+ 140, 141, 142, 143, 0, 0, 0, 144, 145, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 146, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 192, 147, 148, 0,
+ 149, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 59, 139, 60, 140, 141, 142, 143,
+ 0, 0, 0, 144, 145, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 134, 2,
+ 3, 4, 146, 6, 7, 8, 9, 10, 11, 0,
+ 0, 0, 192, 147, 148, 0, 149, 0, 0, 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 0, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 0, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 0, 56, 57, 58,
+ 59, 139, 60, 140, 141, 142, 143, 0, 0, 0,
+ 144, 145, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 3, 4, 0, 0, 146,
+ 8, 9, 10, 11, 0, 0, 0, 0, 0, 0,
+ 147, 148, 0, 149, 0, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 0, 0, 0, 0, 0, 31, 32, 33, 34, 35,
+ 36, 0, 0, 0, 40, 41, 0, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 0, 56, 57, 58, 0, 107, 60, 0, 0,
+ 8, 9, 10, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 0, 0, 0, 0, 108, 31, 32, 33, 34, 35,
+ 36, 0, 0, 0, 40, 41, 0, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 0, 56, 57, 58, 0, 139, 60, 140, 141,
+ 142, 143, 0, 0, 0, 144, 145, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 146, 0, 0, 214, 8, 9,
+ 10, 11, 0, 0, 0, 147, 148, 0, 149, 0,
+ 0, 0, 0, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 0, 0,
+ 0, 0, 0, 31, 32, 33, 34, 35, 36, 0,
+ 0, 0, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 0, 139, 60, 140, 141, 142, 143,
+ 0, 0, 0, 144, 145, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 146, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 264, 147, 148, 0, 149, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 0, 0, 0, 0, 0, 31, 32,
+ 33, 34, 35, 36, 0, 0, 0, 40, 41, 0,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 0, 56, 57, 58, 0, 139,
+ 60, 140, 141, 142, 143, 0, 0, 0, 144, 145,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 146, 0, 0,
+ 280, 8, 9, 10, 11, 0, 0, 0, 147, 148,
+ 0, 149, 0, 0, 0, 0, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 0, 0, 0, 0, 0, 31, 32, 33, 34,
+ 35, 36, 0, 0, 0, 40, 41, 0, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 0, 56, 57, 58, 0, 139, 60, 140,
+ 141, 142, 143, 0, 0, 0, 144, 145, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 146, 8, 9, 10, 11,
+ 0, 0, 0, 0, 0, 0, 147, 148, 0, 149,
+ 0, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 0, 0, 0, 0,
+ 0, 31, 32, 33, 34, 35, 36, 0, 0, 0,
+ 40, 234, 0, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 0, 56, 57,
+ 58, 0, 139, 60, 140, 141, 142, 143, 0, 0,
+ 0, 144, 145, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 134, 2, 3, 4,
+ 146, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 147, 148, 0, 149, 0, 0, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 0,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 0, 56, 57, 58, 59, 0,
+ 60, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 134, 2, 3, 4, 0, 6, 7, 8, 9,
+ 10, 11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 222, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 59, 0, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 134, 2, 3, 4,
+ 0, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 253, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 0,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 0, 56, 57, 58, 59, 0,
+ 60, 0, 0, 0, 0, 0, 0, 0, 114, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 312, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 59, 0, 60, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 0,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 0, 56, 57, 58, 59, 0,
+ 60, 134, 2, 3, 4, 0, 6, 7, 8, 9,
+ 10, 11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 59, 0, 60, 2, 3, 4, 0,
+ 0, 0, 8, 9, 10, 11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 0, 0, 0, 0, 0, 31, 32, 33,
+ 34, 35, 36, 0, 0, 0, 40, 41, 0, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 0, 56, 57, 58, 0, 0, 60,
+ 8, 9, 10, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 0, 0, 0, 0, 0, 31, 32, 33, 34, 35,
+ 36, 0, 0, 0, 40, 41, 0, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 0, 56, 57, 58, 0, 293, 294, 8, 9,
+ 10, 11, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 0, 0,
+ 0, 0, 0, 31, 32, 33, 34, 35, 36, 0,
+ 0, 0, 40, 41, 0, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 0,
+ 56, 57, 58, 0, 0, 60
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-309)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 40, 92, 113, 70, 213, 132, 109, 146, 131,
+ 204, 0, 137, 117, 9, 117, 0, 44, 76, 315,
+ 319, 131, 105, 9, 111, 87, 88, 114, 111, 68,
+ 338, 92, 158, 106, 100, 137, 76, 77, 337, 69,
+ 116, 114, 118, 109, 74, 40, 41, 42, 9, 76,
+ 188, 117, 177, 361, 40, 41, 114, 43, 104, 355,
+ 122, 123, 128, 102, 360, 51, 127, 73, 108, 135,
+ 70, 137, 114, 73, 178, 177, 178, 83, 78, 40,
+ 41, 42, 105, 83, 94, 95, 96, 213, 127, 78,
+ 212, 229, 106, 103, 78, 85, 86, 106, 111, 113,
+ 100, 114, 212, 113, 113, 106, 104, 233, 106, 109,
+ 105, 177, 178, 251, 113, 111, 106, 117, 114, 111,
+ 110, 108, 122, 76, 262, 105, 320, 105, 128, 254,
+ 105, 111, 131, 111, 105, 135, 111, 137, 40, 41,
+ 111, 242, 243, 244, 245, 144, 145, 111, 274, 275,
+ 114, 108, 254, 111, 362, 104, 114, 279, 4, 5,
+ 6, 113, 161, 285, 40, 41, 42, 76, 77, 279,
+ 76, 77, 119, 120, 108, 285, 114, 177, 178, 89,
+ 90, 319, 79, 80, 111, 112, 240, 241, 254, 246,
+ 247, 230, 44, 104, 93, 91, 114, 105, 114, 337,
+ 104, 104, 107, 104, 204, 331, 328, 114, 108, 104,
+ 348, 109, 106, 212, 107, 106, 104, 319, 328, 111,
+ 107, 359, 107, 104, 314, 56, 104, 107, 107, 17,
+ 105, 114, 109, 107, 105, 337, 362, 230, 249, 238,
+ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
+ 249, 250, 113, 250, 254, 114, 114, 248, 128, 94,
+ 101, 128, 5, 218, 181, 286, 316, 360, 268, 316,
+ 337, 78, -1, -1, 268, 341, -1, -1, -1, -1,
+ 279, -1, -1, -1, -1, -1, 285, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 340, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 315, 316, -1, -1, 319,
+ 320, -1, -1, -1, -1, -1, -1, -1, -1, 328,
+ -1, -1, -1, -1, -1, -1, -1, 337, -1, -1,
+ -1, 341, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 355, -1, -1, -1, -1,
+ 360, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, -1, 18, 19, 20, 21,
+ -1, -1, -1, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ -1, -1, -1, 85, 86, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 104, -1, -1, -1, 108, 109, -1, -1,
+ -1, -1, 114, 115, 116, -1, 118, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, -1, 18, 19, 20, 21, -1, -1, -1, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, -1, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, -1, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, -1, -1, -1, 85,
+ 86, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 104, -1,
+ -1, -1, 108, 109, -1, -1, -1, -1, 114, 115,
+ 116, -1, 118, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, -1, 18, 19,
+ 20, 21, -1, -1, -1, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, -1, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, -1, -1, -1, 85, 86, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 104, -1, -1, -1, 108, -1,
+ -1, -1, -1, -1, 114, 115, 116, -1, 118, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, -1, 18, 19, 20, 21, -1, -1,
+ -1, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, -1, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, -1, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, -1, -1,
+ -1, 85, 86, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 104, -1, -1, -1, 108, -1, -1, -1, -1, -1,
+ 114, 115, 116, -1, 118, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, -1,
+ 18, 19, 20, 21, -1, -1, -1, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, -1, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, -1, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, -1, -1, -1, 85, 86, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 104, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 114, 115, 116, -1,
+ 118, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ -1, -1, -1, 85, 86, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 3, 4,
+ 5, 6, 104, 8, 9, 10, 11, 12, 13, -1,
+ -1, -1, 114, 115, 116, -1, 118, -1, -1, -1,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, -1, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, -1, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, -1, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, -1, -1, -1,
+ 85, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 4, 5, 6, -1, -1, 104,
+ 10, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ 115, 116, -1, 118, -1, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ -1, -1, -1, -1, -1, 45, 46, 47, 48, 49,
+ 50, -1, -1, -1, 54, 55, -1, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, -1, 76, 77, -1, -1,
+ 10, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ -1, -1, -1, -1, 114, 45, 46, 47, 48, 49,
+ 50, -1, -1, -1, 54, 55, -1, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, -1, 76, 77, 78, 79,
+ 80, 81, -1, -1, -1, 85, 86, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 104, -1, -1, 107, 10, 11,
+ 12, 13, -1, -1, -1, 115, 116, -1, 118, -1,
+ -1, -1, -1, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, -1, -1,
+ -1, -1, -1, 45, 46, 47, 48, 49, 50, -1,
+ -1, -1, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, -1, 76, 77, 78, 79, 80, 81,
+ -1, -1, -1, 85, 86, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 104, 10, 11, 12, 13, -1, -1, -1,
+ -1, -1, 114, 115, 116, -1, 118, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, -1, -1, -1, 45, 46,
+ 47, 48, 49, 50, -1, -1, -1, 54, 55, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, -1, 76,
+ 77, 78, 79, 80, 81, -1, -1, -1, 85, 86,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 104, -1, -1,
+ 107, 10, 11, 12, 13, -1, -1, -1, 115, 116,
+ -1, 118, -1, -1, -1, -1, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, -1, -1, -1, 45, 46, 47, 48,
+ 49, 50, -1, -1, -1, 54, 55, -1, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, -1, 72, 73, 74, -1, 76, 77, 78,
+ 79, 80, 81, -1, -1, -1, 85, 86, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 104, 10, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, 115, 116, -1, 118,
+ -1, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, -1, -1, -1, -1,
+ -1, 45, 46, 47, 48, 49, 50, -1, -1, -1,
+ 54, 55, -1, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, -1, 72, 73,
+ 74, -1, 76, 77, 78, 79, 80, 81, -1, -1,
+ -1, 85, 86, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 3, 4, 5, 6,
+ 104, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, 115, 116, -1, 118, -1, -1, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, -1, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, 75, -1,
+ 77, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, -1, 8, 9, 10, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 109, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, 75, -1, 77, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 3, 4, 5, 6,
+ -1, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 109, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, -1, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, 75, -1,
+ 77, -1, -1, -1, -1, -1, -1, -1, 0, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 109, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, 75, -1, 77, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, -1, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, -1,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, 75, -1,
+ 77, 3, 4, 5, 6, -1, 8, 9, 10, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, 75, -1, 77, 4, 5, 6, -1,
+ -1, -1, 10, 11, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, -1, -1, -1, 45, 46, 47,
+ 48, 49, 50, -1, -1, -1, 54, 55, -1, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, -1, 72, 73, 74, -1, -1, 77,
+ 10, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ -1, -1, -1, -1, -1, 45, 46, 47, 48, 49,
+ 50, -1, -1, -1, 54, 55, -1, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, -1, 76, 77, 10, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, -1, -1,
+ -1, -1, -1, 45, 46, 47, 48, 49, 50, -1,
+ -1, -1, 54, 55, -1, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, -1, -1, 77
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 72, 73, 74, 75,
+ 77, 160, 161, 162, 163, 164, 169, 170, 171, 172,
+ 174, 175, 176, 177, 178, 181, 182, 183, 215, 216,
+ 217, 44, 76, 177, 40, 41, 76, 77, 108, 129,
+ 104, 114, 218, 105, 111, 9, 40, 41, 42, 166,
+ 167, 173, 111, 114, 76, 129, 175, 76, 114, 159,
+ 176, 181, 175, 106, 0, 216, 181, 185, 108, 76,
+ 179, 180, 108, 201, 166, 165, 168, 176, 167, 129,
+ 104, 106, 113, 108, 3, 174, 176, 186, 187, 76,
+ 78, 79, 80, 81, 85, 86, 104, 115, 116, 118,
+ 130, 131, 132, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 158, 182, 114, 186, 184, 113,
+ 105, 111, 14, 15, 16, 18, 19, 20, 21, 56,
+ 108, 109, 114, 141, 154, 155, 157, 160, 161, 182,
+ 191, 192, 193, 194, 202, 203, 204, 207, 214, 129,
+ 165, 168, 106, 113, 107, 158, 155, 190, 176, 129,
+ 188, 189, 109, 187, 141, 141, 157, 85, 86, 106,
+ 110, 105, 105, 111, 55, 155, 104, 141, 119, 120,
+ 116, 118, 87, 88, 122, 123, 89, 90, 91, 93,
+ 92, 127, 107, 109, 186, 79, 80, 180, 114, 114,
+ 209, 104, 104, 114, 114, 157, 104, 109, 195, 94,
+ 95, 96, 103, 113, 156, 111, 114, 109, 192, 106,
+ 107, 158, 190, 107, 188, 106, 111, 114, 76, 114,
+ 105, 133, 157, 76, 77, 129, 136, 155, 141, 141,
+ 143, 143, 145, 145, 145, 145, 146, 146, 150, 151,
+ 152, 157, 109, 198, 199, 200, 210, 157, 114, 208,
+ 202, 155, 155, 158, 107, 114, 158, 189, 106, 114,
+ 107, 112, 56, 201, 193, 191, 203, 211, 105, 157,
+ 171, 174, 206, 196, 107, 107, 158, 155, 104, 206,
+ 212, 213, 198, 205, 129, 105, 109, 107, 157, 114,
+ 105, 17, 113, 193, 197, 201, 114, 105, 157, 197,
+ 198, 190, 114
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+#else
+static unsigned
+yy_location_print_ (yyo, yylocp)
+ FILE *yyo;
+ YYLTYPE const * const yylocp;
+#endif
+{
+ unsigned res = 0;
+ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+ if (0 <= yylocp->first_line)
+ {
+ res += fprintf (yyo, "%d", yylocp->first_line);
+ if (0 <= yylocp->first_column)
+ res += fprintf (yyo, ".%d", yylocp->first_column);
+ }
+ if (0 <= yylocp->last_line)
+ {
+ if (yylocp->first_line < yylocp->last_line)
+ {
+ res += fprintf (yyo, "-%d", yylocp->last_line);
+ if (0 <= end_col)
+ res += fprintf (yyo, ".%d", end_col);
+ }
+ else if (0 <= end_col && yylocp->first_column < end_col)
+ res += fprintf (yyo, "-%d", end_col);
+ }
+ return res;
+ }
+
+# define YY_LOCATION_PRINT(File, Loc) \
+ yy_location_print_ (File, &(Loc))
+
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, Location, context); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ TParseContext* context;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+ YYUSE (yylocationp);
+ YYUSE (context);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ TParseContext* context;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, TParseContext* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+ YYSTYPE *yyvsp;
+ YYLTYPE *yylsp;
+ int yyrule;
+ TParseContext* context;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , &(yylsp[(yyi + 1) - (yynrhs)]) , context);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, TParseContext* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+ TParseContext* context;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+ YYUSE (context);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YYUSE (yytype);
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (TParseContext* context)
+#else
+int
+yyparse (context)
+ TParseContext* context;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+ = { 1, 1, 1, 1 }
+# endif
+;
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+/* Location data for the lookahead symbol. */
+YYLTYPE yylloc = yyloc_default;
+
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ `yyls': related to locations.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls;
+ YYLTYPE *yylsp;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[3];
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yylsp = yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ yylsp[0] = yylloc;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+
+ {
+ // The symbol table search was done in the lexical phase
+ const TSymbol *symbol = (yyvsp[(1) - (1)].lex).symbol;
+ const TVariable *variable = 0;
+
+ if (!symbol)
+ {
+ context->error((yylsp[(1) - (1)]), "undeclared identifier", (yyvsp[(1) - (1)].lex).string->c_str());
+ context->recover();
+ }
+ else if (!symbol->isVariable())
+ {
+ context->error((yylsp[(1) - (1)]), "variable expected", (yyvsp[(1) - (1)].lex).string->c_str());
+ context->recover();
+ }
+ else
+ {
+ variable = static_cast<const TVariable*>(symbol);
+
+ if (context->symbolTable.findBuiltIn(variable->getName(), context->shaderVersion) &&
+ !variable->getExtension().empty() &&
+ context->extensionErrorCheck((yylsp[(1) - (1)]), variable->getExtension()))
+ {
+ context->recover();
+ }
+ }
+
+ if (!variable)
+ {
+ TType type(EbtFloat, EbpUndefined);
+ TVariable *fakeVariable = new TVariable((yyvsp[(1) - (1)].lex).string, type);
+ context->symbolTable.declare(*fakeVariable);
+ variable = fakeVariable;
+ }
+
+ if (variable->getType().getQualifier() == EvqConst)
+ {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[(1) - (1)]));
+ }
+ else
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ (yylsp[(1) - (1)]));
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+ }
+ break;
+
+ case 5:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 6:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst((yyvsp[(1) - (1)].lex).i);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 7:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setUConst((yyvsp[(1) - (1)].lex).u);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 8:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst((yyvsp[(1) - (1)].lex).f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 9:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst((yyvsp[(1) - (1)].lex).b);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 10:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode);
+ }
+ break;
+
+ case 11:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 12:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[(1) - (4)].interm.intermTypedNode), (yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode));
+ }
+ break;
+
+ case 13:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 14:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addFieldSelectionExpression((yyvsp[(1) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yylsp[(3) - (3)]));
+ }
+ break;
+
+ case 15:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 16:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 17:
+
+ {
+ if (context->integerErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]"))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 18:
+
+ {
+ TFunction* fnCall = (yyvsp[(1) - (1)].interm).function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck((yylsp[(1) - (1)]), (yyvsp[(1) - (1)].interm).intermNode, *fnCall, op, &type)) {
+ (yyval.interm.intermTypedNode) = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[(1) - (1)].interm).intermNode, &type, op, fnCall, (yylsp[(1) - (1)]));
+ }
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yylsp[(1) - (1)]));
+ }
+ (yyval.interm.intermTypedNode)->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction((yylsp[(1) - (1)]), fnCall, context->shaderVersion, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck((yylsp[(1) - (1)]), fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[(1) - (1)].interm).intermNode, (yylsp[(1) - (1)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>((yyvsp[(1) - (1)].interm).intermNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ YYERROR;
+ }
+ } else {
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, op, (yylsp[(1) - (1)]));
+ }
+ } else {
+ // This is a real function call
+
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, EOpFunctionCall, (yylsp[(1) - (1)]));
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setUserDefined();
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ context->recover();
+ }
+ }
+ }
+ }
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ break;
+
+ case 19:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ }
+ break;
+
+ case 20:
+
+ {
+ context->error((yylsp[(3) - (3)]), "methods are not supported", "");
+ context->recover();
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ }
+ break;
+
+ case 21:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ }
+ break;
+
+ case 22:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ }
+ break;
+
+ case 23:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = 0;
+ }
+ break;
+
+ case 24:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (1)].interm.function);
+ (yyval.interm).intermNode = 0;
+ }
+ break;
+
+ case 25:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(2) - (2)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (2)].interm.function)->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ break;
+
+ case 26:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(3) - (3)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (3)].interm).function->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (3)].interm).function;
+ (yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ }
+ break;
+
+ case 27:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ }
+ break;
+
+ case 28:
+
+ {
+ (yyval.interm.function) = context->addConstructorFunc((yyvsp[(1) - (1)].interm.type));
+ }
+ break;
+
+ case 29:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type);
+ (yyval.interm.function) = function;
+ }
+ break;
+
+ case 30:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 31:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 32:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 33:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).op != EOpNull) {
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath((yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ const char* errorOp = "";
+ switch((yyvsp[(1) - (2)].interm).op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError((yylsp[(1) - (2)]), errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ } else
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ break;
+
+ case 34:
+
+ { (yyval.interm).op = EOpNull; }
+ break;
+
+ case 35:
+
+ { (yyval.interm).op = EOpNegative; }
+ break;
+
+ case 36:
+
+ { (yyval.interm).op = EOpLogicalNot; }
+ break;
+
+ case 37:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 38:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 39:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 40:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 41:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "+", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 42:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "-", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 43:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 44:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 45:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "<", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 46:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ">", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 47:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "<=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 48:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ">=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 49:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 50:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "==", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 51:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "!=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 52:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 53:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 54:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 55:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 56:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "&&", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 57:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 58:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "^^", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 59:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 60:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "||", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 61:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 62:
+
+ {
+ if (context->boolErrorCheck((yylsp[(2) - (5)]), (yyvsp[(1) - (5)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermTypedNode) = context->intermediate.addSelection((yyvsp[(1) - (5)].interm.intermTypedNode), (yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.intermTypedNode), (yylsp[(2) - (5)]));
+ if ((yyvsp[(3) - (5)].interm.intermTypedNode)->getType() != (yyvsp[(5) - (5)].interm.intermTypedNode)->getType())
+ (yyval.interm.intermTypedNode) = 0;
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (5)]), ":", (yyvsp[(3) - (5)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(5) - (5)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(5) - (5)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 63:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 64:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->assignError((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 65:
+
+ { (yyval.interm).op = EOpAssign; }
+ break;
+
+ case 66:
+
+ { (yyval.interm).op = EOpMulAssign; }
+ break;
+
+ case 67:
+
+ { (yyval.interm).op = EOpDivAssign; }
+ break;
+
+ case 68:
+
+ { (yyval.interm).op = EOpAddAssign; }
+ break;
+
+ case 69:
+
+ { (yyval.interm).op = EOpSubAssign; }
+ break;
+
+ case 70:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 71:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 72:
+
+ {
+ if (context->constErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 73:
+
+ {
+ if (context->enterStructDeclaration((yylsp[(1) - (2)]), *(yyvsp[(1) - (2)].lex).string))
+ context->recover();
+ (yyval.lex) = (yyvsp[(1) - (2)].lex);
+ }
+ break;
+
+ case 74:
+
+ {
+ TFunction &function = *((yyvsp[(1) - (2)].interm).function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), (yylsp[(1) - (2)])), (yylsp[(1) - (2)]));
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (2)])), (yylsp[(1) - (2)]));
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ (yyval.interm.intermNode) = prototype;
+
+ context->symbolTable.pop();
+ }
+ break;
+
+ case 75:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).intermAggregate)
+ (yyvsp[(1) - (2)].interm).intermAggregate->setOp(EOpDeclaration);
+ (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermAggregate;
+ }
+ break;
+
+ case 76:
+
+ {
+ if (((yyvsp[(2) - (4)].interm.precision) == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
+ context->error((yylsp[(1) - (4)]), "precision is not supported in fragment shader", "highp");
+ context->recover();
+ }
+ if (!context->symbolTable.setDefaultPrecision( (yyvsp[(3) - (4)].interm.type), (yyvsp[(2) - (4)].interm.precision) )) {
+ context->error((yylsp[(1) - (4)]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[(3) - (4)].interm.type).type));
+ context->recover();
+ }
+ (yyval.interm.intermNode) = 0;
+ }
+ break;
+
+ case 77:
+
+ {
+ ES3_ONLY(getQualifierString((yyvsp[(1) - (5)].interm.type).qualifier), (yylsp[(1) - (5)]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (5)].interm.type), (yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yyvsp[(3) - (5)].interm.fieldList), NULL, (yyloc), NULL, (yyloc));
+ }
+ break;
+
+ case 78:
+
+ {
+ ES3_ONLY(getQualifierString((yyvsp[(1) - (6)].interm.type).qualifier), (yylsp[(1) - (6)]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (6)].interm.type), (yylsp[(2) - (6)]), *(yyvsp[(2) - (6)].lex).string, (yyvsp[(3) - (6)].interm.fieldList), (yyvsp[(5) - (6)].lex).string, (yylsp[(5) - (6)]), NULL, (yyloc));
+ }
+ break;
+
+ case 79:
+
+ {
+ ES3_ONLY(getQualifierString((yyvsp[(1) - (9)].interm.type).qualifier), (yylsp[(1) - (9)]), "interface blocks");
+ (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (9)].interm.type), (yylsp[(2) - (9)]), *(yyvsp[(2) - (9)].lex).string, (yyvsp[(3) - (9)].interm.fieldList), (yyvsp[(5) - (9)].lex).string, (yylsp[(5) - (9)]), (yyvsp[(7) - (9)].interm.intermTypedNode), (yylsp[(6) - (9)]));
+ }
+ break;
+
+ case 80:
+
+ {
+ context->parseGlobalLayoutQualifier((yyvsp[(1) - (2)].interm.type));
+ (yyval.interm.intermNode) = 0;
+ }
+ break;
+
+ case 81:
+
+ {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getMangledName(), context->shaderVersion));
+ if (prevDec) {
+ if (prevDec->getReturnType() != (yyvsp[(1) - (2)].interm.function)->getReturnType()) {
+ context->error((yylsp[(2) - (2)]), "overloaded functions must have the same return type", (yyvsp[(1) - (2)].interm.function)->getReturnType().getBasicString());
+ context->recover();
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifier()) {
+ context->error((yylsp[(2) - (2)]), "overloaded functions must have the same parameter qualifiers", (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifierString());
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getName(), context->shaderVersion);
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ context->error((yylsp[(2) - (2)]), "redefinition", (yyvsp[(1) - (2)].interm.function)->getName().c_str(), "function");
+ context->recover();
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ context->symbolTable.getOuterLevel()->insert((yyvsp[(1) - (2)].interm.function)->getName(), *(yyvsp[(1) - (2)].interm.function));
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ context->symbolTable.getOuterLevel()->insert(*(yyval.interm).function);
+ }
+ break;
+
+ case 82:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ }
+ break;
+
+ case 83:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ }
+ break;
+
+ case 84:
+
+ {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid)
+ (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param);
+ else
+ delete (yyvsp[(2) - (2)].interm).param.type;
+ }
+ break;
+
+ case 85:
+
+ {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ((yyvsp[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error((yylsp[(2) - (3)]), "cannot be an argument type except for '(void)'", "void");
+ context->recover();
+ delete (yyvsp[(3) - (3)].interm).param.type;
+ } else {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function);
+ (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param);
+ }
+ }
+ break;
+
+ case 86:
+
+ {
+ if ((yyvsp[(1) - (3)].interm.type).qualifier != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier != EvqTemporary) {
+ context->error((yylsp[(2) - (3)]), "no qualifiers allowed for function return", getQualifierString((yyvsp[(1) - (3)].interm.type).qualifier));
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck((yylsp[(2) - (3)]), (yyvsp[(1) - (3)].interm.type)))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type((yyvsp[(1) - (3)].interm.type));
+ function = new TFunction((yyvsp[(2) - (3)].lex).string, type);
+ (yyval.interm.function) = function;
+
+ context->symbolTable.push();
+ }
+ break;
+
+ case 87:
+
+ {
+ if ((yyvsp[(1) - (2)].interm.type).type == EbtVoid) {
+ context->error((yylsp[(2) - (2)]), "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str());
+ context->recover();
+ }
+ if (context->reservedErrorCheck((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string))
+ context->recover();
+ TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))};
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 88:
+
+ {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ if (context->reservedErrorCheck((yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+ (yyvsp[(1) - (5)].interm.type).setArray(true, size);
+
+ TType* type = new TType((yyvsp[(1) - (5)].interm.type));
+ TParameter param = { (yyvsp[(2) - (5)].lex).string, type };
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 89:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.qualifier), (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 90:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 91:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.qualifier), (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 92:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 93:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ }
+ break;
+
+ case 94:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ }
+ break;
+
+ case 95:
+
+ {
+ (yyval.interm.qualifier) = EvqOut;
+ }
+ break;
+
+ case 96:
+
+ {
+ (yyval.interm.qualifier) = EvqInOut;
+ }
+ break;
+
+ case 97:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) };
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 98:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ }
+ break;
+
+ case 99:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (3)].interm);
+ (yyval.interm).intermAggregate = context->parseDeclarator((yyval.interm).type, (yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].lex).symbol, (yylsp[(3) - (3)]), *(yyvsp[(3) - (3)].lex).string);
+ }
+ break;
+
+ case 100:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+ context->parseArrayDeclarator((yyval.interm).type, (yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yylsp[(4) - (5)]), NULL, NULL);
+ }
+ break;
+
+ case 101:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (6)].interm);
+ (yyval.interm).intermAggregate = context->parseArrayDeclarator((yyval.interm).type, (yylsp[(3) - (6)]), *(yyvsp[(3) - (6)].lex).string, (yylsp[(4) - (6)]), (yyvsp[(1) - (6)].interm).intermNode, (yyvsp[(5) - (6)].interm.intermTypedNode));
+ }
+ break;
+
+ case 102:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+ (yyval.interm).intermAggregate = context->parseInitDeclarator((yyval.interm).type, (yyvsp[(1) - (5)].interm).intermAggregate, (yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yylsp[(4) - (5)]), (yyvsp[(5) - (5)].interm.intermTypedNode));
+ }
+ break;
+
+ case 103:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(1) - (1)]), "");
+ }
+ break;
+
+ case 104:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (2)].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string);
+ }
+ break;
+
+ case 105:
+
+ {
+ context->error((yylsp[(2) - (4)]), "unsized array declarations not supported", (yyvsp[(2) - (4)].lex).string->c_str());
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string);
+ }
+ break;
+
+ case 106:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (5)].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode));
+ }
+ break;
+
+ case 107:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+ (yyval.interm).intermAggregate = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yylsp[(3) - (4)]), (yyvsp[(4) - (4)].interm.intermTypedNode));
+ }
+ break;
+
+ case 108:
+
+ {
+ VERTEX_ONLY("invariant declaration", (yylsp[(1) - (2)]));
+ if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ (yyval.interm).type.setBasic(EbtInvariant, EvqInvariantVaryingOut, (yylsp[(2) - (2)]));
+ if (!(yyvsp[(2) - (2)].lex).symbol)
+ {
+ context->error((yylsp[(2) - (2)]), "undeclared identifier declared as invariant", (yyvsp[(2) - (2)].lex).string->c_str());
+ context->recover();
+
+ (yyval.interm).intermAggregate = 0;
+ }
+ else
+ {
+ TIntermSymbol *symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyval.interm).type), (yylsp[(2) - (2)]));
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (2)]));
+ }
+ }
+ break;
+
+ case 109:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyvsp[(1) - (1)].interm.type).array) {
+ context->error((yylsp[(1) - (1)]), "not supported", "first-class array");
+ context->recover();
+ (yyvsp[(1) - (1)].interm.type).setArray(false);
+ }
+ }
+ break;
+
+ case 110:
+
+ {
+ (yyval.interm.type) = context->addFullySpecifiedType((yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(1) - (2)].interm.type).layoutQualifier, (yyvsp[(2) - (2)].interm.type));
+ }
+ break;
+
+ case 111:
+
+ {
+ (yyval.interm.type).qualifier = EvqSmooth;
+ }
+ break;
+
+ case 112:
+
+ {
+ (yyval.interm.type).qualifier = EvqFlat;
+ }
+ break;
+
+ case 113:
+
+ {
+ (yyval.interm.qualifier) = EvqConst;
+ }
+ break;
+
+ case 114:
+
+ {
+ VERTEX_ONLY("attribute", (yylsp[(1) - (1)]));
+ ES2_ONLY("attribute", (yylsp[(1) - (1)]));
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 115:
+
+ {
+ ES2_ONLY("varying", (yylsp[(1) - (1)]));
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yylsp[(1) - (1)]));
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 116:
+
+ {
+ ES2_ONLY("varying", (yylsp[(1) - (2)]));
+ if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingOut, (yylsp[(1) - (2)]));
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingIn, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 117:
+
+ {
+ if ((yyvsp[(1) - (1)].interm.type).qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) {
+ context->error((yylsp[(1) - (1)]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[(1) - (1)].interm.type).qualifier));
+ context->recover();
+ } else {
+ (yyval.interm.type).setBasic(EbtVoid, (yyvsp[(1) - (1)].interm.type).qualifier, (yylsp[(1) - (1)]));
+ }
+ }
+ break;
+
+ case 118:
+
+ {
+ (yyval.interm.type) = context->joinInterpolationQualifiers((yylsp[(1) - (2)]), (yyvsp[(1) - (2)].interm.type).qualifier, (yylsp[(2) - (2)]), (yyvsp[(2) - (2)].interm.type).qualifier);
+ }
+ break;
+
+ case 119:
+
+ {
+ context->error((yylsp[(1) - (1)]), "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString((yyvsp[(1) - (1)].interm.type).qualifier));
+ context->recover();
+
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 120:
+
+ {
+ (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).layoutQualifier = (yyvsp[(1) - (1)].interm.layoutQualifier);
+ }
+ break;
+
+ case 121:
+
+ {
+ (yyval.interm.type).setBasic(EbtVoid, (yyvsp[(2) - (2)].interm.type).qualifier, (yylsp[(2) - (2)]));
+ (yyval.interm.type).layoutQualifier = (yyvsp[(1) - (2)].interm.layoutQualifier);
+ }
+ break;
+
+ case 122:
+
+ {
+ (yyval.interm.type).qualifier = EvqConst;
+ }
+ break;
+
+ case 123:
+
+ {
+ ES3_ONLY("in", (yylsp[(1) - (1)]), "storage qualifier");
+ (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
+ }
+ break;
+
+ case 124:
+
+ {
+ ES3_ONLY("out", (yylsp[(1) - (1)]), "storage qualifier");
+ (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
+ }
+ break;
+
+ case 125:
+
+ {
+ ES3_ONLY("centroid in", (yylsp[(1) - (2)]), "storage qualifier");
+ if (context->shaderType == SH_VERTEX_SHADER)
+ {
+ context->error((yylsp[(1) - (2)]), "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
+ context->recover();
+ }
+ (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
+ }
+ break;
+
+ case 126:
+
+ {
+ ES3_ONLY("centroid out", (yylsp[(1) - (2)]), "storage qualifier");
+ if (context->shaderType == SH_FRAGMENT_SHADER)
+ {
+ context->error((yylsp[(1) - (2)]), "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
+ context->recover();
+ }
+ (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
+ }
+ break;
+
+ case 127:
+
+ {
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ (yyval.interm.type).qualifier = EvqUniform;
+ }
+ break;
+
+ case 128:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyval.interm.type).precision == EbpUndefined) {
+ (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[(1) - (1)].interm.type).type);
+ if (context->precisionErrorCheck((yylsp[(1) - (1)]), (yyval.interm.type).precision, (yyvsp[(1) - (1)].interm.type).type)) {
+ context->recover();
+ }
+ }
+ }
+ break;
+
+ case 129:
+
+ {
+ (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+ (yyval.interm.type).precision = (yyvsp[(1) - (2)].interm.precision);
+
+ if (!SupportsPrecision((yyvsp[(2) - (2)].interm.type).type)) {
+ context->error((yylsp[(1) - (2)]), "illegal type for precision qualifier", getBasicString((yyvsp[(2) - (2)].interm.type).type));
+ context->recover();
+ }
+ }
+ break;
+
+ case 130:
+
+ {
+ (yyval.interm.precision) = EbpHigh;
+ }
+ break;
+
+ case 131:
+
+ {
+ (yyval.interm.precision) = EbpMedium;
+ }
+ break;
+
+ case 132:
+
+ {
+ (yyval.interm.precision) = EbpLow;
+ }
+ break;
+
+ case 133:
+
+ {
+ ES3_ONLY("layout", (yylsp[(1) - (4)]), "qualifier");
+ (yyval.interm.layoutQualifier) = (yyvsp[(3) - (4)].interm.layoutQualifier);
+ }
+ break;
+
+ case 134:
+
+ {
+ (yyval.interm.layoutQualifier) = (yyvsp[(1) - (1)].interm.layoutQualifier);
+ }
+ break;
+
+ case 135:
+
+ {
+ (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[(1) - (3)].interm.layoutQualifier), (yyvsp[(3) - (3)].interm.layoutQualifier));
+ }
+ break;
+
+ case 136:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (1)].lex).string, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 137:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yylsp[(1) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yylsp[(3) - (3)]));
+ }
+ break;
+
+ case 138:
+
+ {
+ (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yylsp[(1) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yylsp[(3) - (3)]));
+ }
+ break;
+
+ case 139:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ }
+ break;
+
+ case 140:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (4)].interm.type);
+
+ if (context->arrayTypeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ (yyval.interm.type).setArray(true, size);
+ }
+ }
+ break;
+
+ case 141:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 142:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 143:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 144:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 145:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 146:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 147:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 148:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 149:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 150:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 151:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 152:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 153:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 154:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 155:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 156:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 157:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 158:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(2, 2);
+ }
+ break;
+
+ case 159:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(3, 3);
+ }
+ break;
+
+ case 160:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(4, 4);
+ }
+ break;
+
+ case 161:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(2, 3);
+ }
+ break;
+
+ case 162:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(3, 2);
+ }
+ break;
+
+ case 163:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(2, 4);
+ }
+ break;
+
+ case 164:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(4, 2);
+ }
+ break;
+
+ case 165:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(3, 4);
+ }
+ break;
+
+ case 166:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setMatrix(4, 3);
+ }
+ break;
+
+ case 167:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 168:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler3D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 169:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 170:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2DArray, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 171:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtISampler2D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 172:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtISampler3D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 173:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtISamplerCube, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 174:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtISampler2DArray, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 175:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUSampler2D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 176:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUSampler3D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 177:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUSamplerCube, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 178:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtUSampler2DArray, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 179:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2DShadow, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 180:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerCubeShadow, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 181:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2DArrayShadow, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 182:
+
+ {
+ if (!context->supportsExtension("GL_OES_EGL_image_external")) {
+ context->error((yylsp[(1) - (1)]), "unsupported type", "samplerExternalOES");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerExternalOES, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 183:
+
+ {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error((yylsp[(1) - (1)]), "unsupported type", "sampler2DRect");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 184:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ break;
+
+ case 185:
+
+ {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>((yyvsp[(1) - (1)].lex).symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtStruct, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).userDef = &structure;
+ }
+ break;
+
+ case 186:
+
+ { if (context->enterStructDeclaration((yylsp[(2) - (3)]), *(yyvsp[(2) - (3)].lex).string)) context->recover(); }
+ break;
+
+ case 187:
+
+ {
+ (yyval.interm.type) = context->addStructure((yylsp[(1) - (6)]), (yylsp[(2) - (6)]), (yyvsp[(2) - (6)].lex).string, (yyvsp[(5) - (6)].interm.fieldList));
+ }
+ break;
+
+ case 188:
+
+ { if (context->enterStructDeclaration((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string)) context->recover(); }
+ break;
+
+ case 189:
+
+ {
+ (yyval.interm.type) = context->addStructure((yylsp[(1) - (5)]), (yyloc), NewPoolTString(""), (yyvsp[(4) - (5)].interm.fieldList));
+ }
+ break;
+
+ case 190:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[(1) - (1)].interm.fieldList);
+ }
+ break;
+
+ case 191:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[(1) - (2)].interm.fieldList);
+ for (size_t i = 0; i < (yyvsp[(2) - (2)].interm.fieldList)->size(); ++i) {
+ TField* field = (*(yyvsp[(2) - (2)].interm.fieldList))[i];
+ for (size_t j = 0; j < (yyval.interm.fieldList)->size(); ++j) {
+ if ((*(yyval.interm.fieldList))[j]->name() == field->name()) {
+ context->error((yylsp[(2) - (2)]), "duplicate field name in structure:", "struct", field->name().c_str());
+ context->recover();
+ }
+ }
+ (yyval.interm.fieldList)->push_back(field);
+ }
+ }
+ break;
+
+ case 192:
+
+ {
+ (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[(1) - (3)].interm.type), (yyvsp[(2) - (3)].interm.fieldList));
+ }
+ break;
+
+ case 193:
+
+ {
+ // ES3 Only, but errors should be handled elsewhere
+ (yyvsp[(2) - (4)].interm.type).qualifier = (yyvsp[(1) - (4)].interm.type).qualifier;
+ (yyvsp[(2) - (4)].interm.type).layoutQualifier = (yyvsp[(1) - (4)].interm.type).layoutQualifier;
+ (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[(2) - (4)].interm.type), (yyvsp[(3) - (4)].interm.fieldList));
+ }
+ break;
+
+ case 194:
+
+ {
+ (yyval.interm.fieldList) = NewPoolTFieldList();
+ (yyval.interm.fieldList)->push_back((yyvsp[(1) - (1)].interm.field));
+ }
+ break;
+
+ case 195:
+
+ {
+ (yyval.interm.fieldList)->push_back((yyvsp[(3) - (3)].interm.field));
+ }
+ break;
+
+ case 196:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ (yyval.interm.field) = new TField(type, (yyvsp[(1) - (1)].lex).string, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 197:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (4)]), *(yyvsp[(1) - (4)].lex).string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(3) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ type->setArraySize(size);
+
+ (yyval.interm.field) = new TField(type, (yyvsp[(1) - (4)].lex).string, (yylsp[(1) - (4)]));
+ }
+ break;
+
+ case 198:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 199:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 200:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); }
+ break;
+
+ case 201:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 202:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 203:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 204:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 205:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 206:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 207:
+
+ { (yyval.interm.intermAggregate) = 0; }
+ break;
+
+ case 208:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 209:
+
+ { context->symbolTable.pop(); }
+ break;
+
+ case 210:
+
+ {
+ if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) {
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setLine((yyloc));
+ }
+ (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate);
+ }
+ break;
+
+ case 211:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 212:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 213:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 214:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); }
+ break;
+
+ case 215:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 216:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); }
+ break;
+
+ case 217:
+
+ {
+ (yyval.interm.intermNode) = 0;
+ }
+ break;
+
+ case 218:
+
+ {
+ if ((yyvsp[(2) - (3)].interm.intermAggregate)) {
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setLine((yyloc));
+ }
+ (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate);
+ }
+ break;
+
+ case 219:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), (yyloc));
+ }
+ break;
+
+ case 220:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), (yyloc));
+ }
+ break;
+
+ case 221:
+
+ { (yyval.interm.intermNode) = 0; }
+ break;
+
+ case 222:
+
+ { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); }
+ break;
+
+ case 223:
+
+ {
+ if (context->boolErrorCheck((yylsp[(1) - (5)]), (yyvsp[(3) - (5)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yylsp[(1) - (5)]));
+ }
+ break;
+
+ case 224:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode);
+ }
+ break;
+
+ case 225:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+ break;
+
+ case 226:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ }
+ break;
+
+ case 227:
+
+ {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ if (context->boolErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+
+ if (!context->executeInitializer((yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode))
+ (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode);
+ else {
+ context->recover();
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ }
+ break;
+
+ case 228:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; }
+ break;
+
+ case 229:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yylsp[(1) - (6)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 230:
+
+ { ++context->loopNestingLevel; }
+ break;
+
+ case 231:
+
+ {
+ if (context->boolErrorCheck((yylsp[(8) - (8)]), (yyvsp[(6) - (8)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yylsp[(4) - (8)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 232:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; }
+ break;
+
+ case 233:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yylsp[(1) - (7)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 234:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 235:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 236:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 237:
+
+ {
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ break;
+
+ case 238:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+ break;
+
+ case 239:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ }
+ break;
+
+ case 240:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yylsp[(1) - (2)]), "continue statement only allowed in loops", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 241:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yylsp[(1) - (2)]), "break statement only allowed in loops", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 242:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[(1) - (2)]));
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error((yylsp[(1) - (2)]), "non-void function must return a value", "return");
+ context->recover();
+ }
+ }
+ break;
+
+ case 243:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yylsp[(1) - (3)]));
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error((yylsp[(1) - (3)]), "void function cannot return a value", "return");
+ context->recover();
+ } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) {
+ context->error((yylsp[(1) - (3)]), "function return is not matching type:", "return");
+ context->recover();
+ }
+ }
+ break;
+
+ case 244:
+
+ {
+ FRAG_ONLY("discard", (yylsp[(1) - (2)]));
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 245:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ context->treeRoot = (yyval.interm.intermNode);
+ }
+ break;
+
+ case 246:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), (yyloc));
+ context->treeRoot = (yyval.interm.intermNode);
+ }
+ break;
+
+ case 247:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 248:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 249:
+
+ {
+ TFunction* function = (yyvsp[(1) - (1)].interm).function;
+
+ const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion);
+
+ if (builtIn)
+ {
+ context->error((yylsp[(1) - (1)]), "built-in functions cannot be redefined", function->getName().c_str());
+ context->recover();
+ }
+
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName(), context->shaderVersion));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error((yylsp[(1) - (1)]), "function already has a body", function->getName().c_str());
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error((yylsp[(1) - (1)]), "function cannot take any parameter(s)", function->getName().c_str());
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error((yylsp[(1) - (1)]), "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.declare(*variable)) {
+ context->error((yylsp[(1) - (1)]), "redefinition", variable->getName().c_str());
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), (yylsp[(1) - (1)])),
+ (yylsp[(1) - (1)]));
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (1)])), (yylsp[(1) - (1)]));
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[(1) - (1)]));
+ (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ break;
+
+ case 250:
+
+ {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error((yylsp[(1) - (3)]), "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str());
+ context->recover();
+ }
+
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].interm.intermNode), (yyloc));
+ context->intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yylsp[(1) - (3)]));
+ (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str());
+ (yyval.interm.intermNode)->getAsAggregate()->setType((yyvsp[(1) - (3)].interm).function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ (yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->pragma().optimize);
+ (yyval.interm.intermNode)->getAsAggregate()->setDebug(context->pragma().debug);
+
+ context->symbolTable.pop();
+ }
+ break;
+
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (&yylloc, context, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (&yylloc, context, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+ yyerror_range[1] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, context);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ yyerror_range[1] = yylsp[1-yylen];
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yylsp, context);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the lookahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, context, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, context);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp, context);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.h b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h
new file mode 100644
index 00000000000..c6a61dcd85f
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h
@@ -0,0 +1,257 @@
+/* A Bison parser, made by GNU Bison 2.7.1. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ UINT_TYPE = 268,
+ BREAK = 269,
+ CONTINUE = 270,
+ DO = 271,
+ ELSE = 272,
+ FOR = 273,
+ IF = 274,
+ DISCARD = 275,
+ RETURN = 276,
+ SWITCH = 277,
+ CASE = 278,
+ DEFAULT = 279,
+ BVEC2 = 280,
+ BVEC3 = 281,
+ BVEC4 = 282,
+ IVEC2 = 283,
+ IVEC3 = 284,
+ IVEC4 = 285,
+ VEC2 = 286,
+ VEC3 = 287,
+ VEC4 = 288,
+ UVEC2 = 289,
+ UVEC3 = 290,
+ UVEC4 = 291,
+ MATRIX2 = 292,
+ MATRIX3 = 293,
+ MATRIX4 = 294,
+ IN_QUAL = 295,
+ OUT_QUAL = 296,
+ INOUT_QUAL = 297,
+ UNIFORM = 298,
+ VARYING = 299,
+ MATRIX2x3 = 300,
+ MATRIX3x2 = 301,
+ MATRIX2x4 = 302,
+ MATRIX4x2 = 303,
+ MATRIX3x4 = 304,
+ MATRIX4x3 = 305,
+ CENTROID = 306,
+ FLAT = 307,
+ SMOOTH = 308,
+ STRUCT = 309,
+ VOID_TYPE = 310,
+ WHILE = 311,
+ SAMPLER2D = 312,
+ SAMPLERCUBE = 313,
+ SAMPLER_EXTERNAL_OES = 314,
+ SAMPLER2DRECT = 315,
+ SAMPLER2DARRAY = 316,
+ ISAMPLER2D = 317,
+ ISAMPLER3D = 318,
+ ISAMPLERCUBE = 319,
+ ISAMPLER2DARRAY = 320,
+ USAMPLER2D = 321,
+ USAMPLER3D = 322,
+ USAMPLERCUBE = 323,
+ USAMPLER2DARRAY = 324,
+ SAMPLER3D = 325,
+ SAMPLER3DRECT = 326,
+ SAMPLER2DSHADOW = 327,
+ SAMPLERCUBESHADOW = 328,
+ SAMPLER2DARRAYSHADOW = 329,
+ LAYOUT = 330,
+ IDENTIFIER = 331,
+ TYPE_NAME = 332,
+ FLOATCONSTANT = 333,
+ INTCONSTANT = 334,
+ UINTCONSTANT = 335,
+ BOOLCONSTANT = 336,
+ FIELD_SELECTION = 337,
+ LEFT_OP = 338,
+ RIGHT_OP = 339,
+ INC_OP = 340,
+ DEC_OP = 341,
+ LE_OP = 342,
+ GE_OP = 343,
+ EQ_OP = 344,
+ NE_OP = 345,
+ AND_OP = 346,
+ OR_OP = 347,
+ XOR_OP = 348,
+ MUL_ASSIGN = 349,
+ DIV_ASSIGN = 350,
+ ADD_ASSIGN = 351,
+ MOD_ASSIGN = 352,
+ LEFT_ASSIGN = 353,
+ RIGHT_ASSIGN = 354,
+ AND_ASSIGN = 355,
+ XOR_ASSIGN = 356,
+ OR_ASSIGN = 357,
+ SUB_ASSIGN = 358,
+ LEFT_PAREN = 359,
+ RIGHT_PAREN = 360,
+ LEFT_BRACKET = 361,
+ RIGHT_BRACKET = 362,
+ LEFT_BRACE = 363,
+ RIGHT_BRACE = 364,
+ DOT = 365,
+ COMMA = 366,
+ COLON = 367,
+ EQUAL = 368,
+ SEMICOLON = 369,
+ BANG = 370,
+ DASH = 371,
+ TILDE = 372,
+ PLUS = 373,
+ STAR = 374,
+ SLASH = 375,
+ PERCENT = 376,
+ LEFT_ANGLE = 377,
+ RIGHT_ANGLE = 378,
+ VERTICAL_BAR = 379,
+ CARET = 380,
+ AMPERSAND = 381,
+ QUESTION = 382
+ };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ unsigned int u;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TLayoutQualifier layoutQualifier;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (TParseContext* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
diff --git a/chromium/third_party/angle/src/compiler/translator/intermOut.cpp b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp
new file mode 100644
index 00000000000..7f94ac31416
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp
@@ -0,0 +1,439 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/localintermediate.h"
+#include "compiler/translator/SymbolTable.h"
+
+//
+// Two purposes:
+// 1. Show an example of how to iterate tree. Functions can
+// also directly call Traverse() on children themselves to
+// have finer grained control over the process than shown here.
+// See the last function for how to get started.
+// 2. Print out a text based description of the tree.
+//
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TOutputTraverser : public TIntermTraverser {
+public:
+ TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
+ TInfoSinkBase& sink;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+};
+
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " " << getPrecisionString() << " ";
+ if (array)
+ stream << "array[" << getArraySize() << "] of ";
+ if (isMatrix())
+ stream << getCols() << "X" << getRows() << " matrix of ";
+ else if (isVector())
+ stream << getNominalSize() << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
+//
+// Helper functions for printing, not part of traversing.
+//
+
+void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
+{
+ int i;
+
+ sink.location(node->getLine());
+
+ for (i = 0; i < depth; ++i)
+ sink << " ";
+}
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol* node)
+{
+ OutputTreeText(sink, node, depth);
+
+ sink << "'" << node->getSymbol() << "' ";
+ sink << "(" << node->getCompleteString() << ")\n";
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpAssign: out << "move second child to first child"; break;
+ case EOpInitialize: out << "initialize first child with second child"; break;
+ case EOpAddAssign: out << "add second child into first child"; break;
+ case EOpSubAssign: out << "subtract second child into first child"; break;
+ case EOpMulAssign: out << "multiply second child into first child"; break;
+ case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break;
+ case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break;
+ case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpDivAssign: out << "divide second child into first child"; break;
+ case EOpIndexDirect: out << "direct index"; break;
+ case EOpIndexIndirect: out << "indirect index"; break;
+ case EOpIndexDirectStruct: out << "direct index for structure"; break;
+ case EOpIndexDirectInterfaceBlock: out << "direct index for interface block"; break;
+ case EOpVectorSwizzle: out << "vector swizzle"; break;
+
+ case EOpAdd: out << "add"; break;
+ case EOpSub: out << "subtract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+ case EOpDiv: out << "divide"; break;
+ case EOpEqual: out << "Compare Equal"; break;
+ case EOpNotEqual: out << "Compare Not Equal"; break;
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+
+ case EOpVectorTimesScalar: out << "vector-scale"; break;
+ case EOpVectorTimesMatrix: out << "vector-times-matrix"; break;
+ case EOpMatrixTimesVector: out << "matrix-times-vector"; break;
+ case EOpMatrixTimesScalar: out << "matrix-scale"; break;
+ case EOpMatrixTimesMatrix: out << "matrix-multiply"; break;
+
+ case EOpLogicalOr: out << "logical-or"; break;
+ case EOpLogicalXor: out << "logical-xor"; break;
+ case EOpLogicalAnd: out << "logical-and"; break;
+ default: out << "<unknown op>";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpNegative: out << "Negate value"; break;
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot: out << "Negate conditional"; break;
+
+ case EOpPostIncrement: out << "Post-Increment"; break;
+ case EOpPostDecrement: out << "Post-Decrement"; break;
+ case EOpPreIncrement: out << "Pre-Increment"; break;
+ case EOpPreDecrement: out << "Pre-Decrement"; break;
+
+ case EOpConvIntToBool: out << "Convert int to bool"; break;
+ case EOpConvUIntToBool: out << "Convert uint to bool"; break;
+ case EOpConvFloatToBool:out << "Convert float to bool";break;
+ case EOpConvBoolToFloat:out << "Convert bool to float";break;
+ case EOpConvIntToFloat: out << "Convert int to float"; break;
+ case EOpConvUIntToFloat:out << "Convert uint to float";break;
+ case EOpConvFloatToInt: out << "Convert float to int"; break;
+ case EOpConvBoolToInt: out << "Convert bool to int"; break;
+ case EOpConvIntToUInt: out << "Convert int to uint"; break;
+ case EOpConvFloatToUInt:out << "Convert float to uint";break;
+ case EOpConvBoolToUInt: out << "Convert bool to uint"; break;
+
+ case EOpRadians: out << "radians"; break;
+ case EOpDegrees: out << "degrees"; break;
+ case EOpSin: out << "sine"; break;
+ case EOpCos: out << "cosine"; break;
+ case EOpTan: out << "tangent"; break;
+ case EOpAsin: out << "arc sine"; break;
+ case EOpAcos: out << "arc cosine"; break;
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpExp: out << "exp"; break;
+ case EOpLog: out << "log"; break;
+ case EOpExp2: out << "exp2"; break;
+ case EOpLog2: out << "log2"; break;
+ case EOpSqrt: out << "sqrt"; break;
+ case EOpInverseSqrt: out << "inverse sqrt"; break;
+
+ case EOpAbs: out << "Absolute value"; break;
+ case EOpSign: out << "Sign"; break;
+ case EOpFloor: out << "Floor"; break;
+ case EOpCeil: out << "Ceiling"; break;
+ case EOpFract: out << "Fraction"; break;
+
+ case EOpLength: out << "length"; break;
+ case EOpNormalize: out << "normalize"; break;
+ // case EOpDPdx: out << "dPdx"; break;
+ // case EOpDPdy: out << "dPdy"; break;
+ // case EOpFwidth: out << "fwidth"; break;
+
+ case EOpAny: out << "any"; break;
+ case EOpAll: out << "all"; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad unary op";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ TInfoSinkBase& out = sink;
+
+ if (node->getOp() == EOpNull) {
+ out.prefix(EPrefixError);
+ out << "node is still EOpNull!";
+ return true;
+ }
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpSequence: out << "Sequence\n"; return true;
+ case EOpComma: out << "Comma\n"; return true;
+ case EOpFunction: out << "Function Definition: " << node->getName(); break;
+ case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
+ case EOpParameters: out << "Function Parameters: "; break;
+
+ case EOpConstructFloat: out << "Construct float"; break;
+ case EOpConstructVec2: out << "Construct vec2"; break;
+ case EOpConstructVec3: out << "Construct vec3"; break;
+ case EOpConstructVec4: out << "Construct vec4"; break;
+ case EOpConstructBool: out << "Construct bool"; break;
+ case EOpConstructBVec2: out << "Construct bvec2"; break;
+ case EOpConstructBVec3: out << "Construct bvec3"; break;
+ case EOpConstructBVec4: out << "Construct bvec4"; break;
+ case EOpConstructInt: out << "Construct int"; break;
+ case EOpConstructIVec2: out << "Construct ivec2"; break;
+ case EOpConstructIVec3: out << "Construct ivec3"; break;
+ case EOpConstructIVec4: out << "Construct ivec4"; break;
+ case EOpConstructUInt: out << "Construct uint"; break;
+ case EOpConstructUVec2: out << "Construct uvec2"; break;
+ case EOpConstructUVec3: out << "Construct uvec3"; break;
+ case EOpConstructUVec4: out << "Construct uvec4"; break;
+ case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat4: out << "Construct mat4"; break;
+ case EOpConstructStruct: out << "Construct structure"; break;
+
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+ case EOpVectorEqual: out << "Equal"; break;
+ case EOpVectorNotEqual: out << "NotEqual"; break;
+
+ case EOpMod: out << "mod"; break;
+ case EOpPow: out << "pow"; break;
+
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpMin: out << "min"; break;
+ case EOpMax: out << "max"; break;
+ case EOpClamp: out << "clamp"; break;
+ case EOpMix: out << "mix"; break;
+ case EOpStep: out << "step"; break;
+ case EOpSmoothStep: out << "smoothstep"; break;
+
+ case EOpDistance: out << "distance"; break;
+ case EOpDot: out << "dot-product"; break;
+ case EOpCross: out << "cross-product"; break;
+ case EOpFaceForward: out << "face-forward"; break;
+ case EOpReflect: out << "reflect"; break;
+ case EOpRefract: out << "refract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+
+ case EOpDeclaration: out << "Declaration: "; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad aggregation op";
+ }
+
+ if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Test condition and select";
+ out << " (" << node->getCompleteString() << ")\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, depth);
+ if (node->getTrueBlock()) {
+ out << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ } else
+ out << "true case is null\n";
+
+ if (node->getFalseBlock()) {
+ OutputTreeText(sink, node, depth);
+ out << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ TInfoSinkBase& out = sink;
+
+ size_t size = node->getType().getObjectSize();
+
+ for (size_t i = 0; i < size; i++) {
+ OutputTreeText(out, node, depth);
+ switch (node->getUnionArrayPointer()[i].getType()) {
+ case EbtBool:
+ if (node->getUnionArrayPointer()[i].getBConst())
+ out << "true";
+ else
+ out << "false";
+
+ out << " (" << "const bool" << ")";
+ out << "\n";
+ break;
+ case EbtFloat:
+ out << node->getUnionArrayPointer()[i].getFConst();
+ out << " (const float)\n";
+ break;
+ case EbtInt:
+ out << node->getUnionArrayPointer()[i].getIConst();
+ out << " (const int)\n";
+ break;
+ case EbtUInt:
+ out << node->getUnionArrayPointer()[i].getUConst();
+ out << " (const uint)\n";
+ break;
+ default:
+ out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ out << "not ";
+ out << "tested first\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ if (node->getCondition()) {
+ out << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ } else
+ out << "No loop condition\n";
+
+ OutputTreeText(sink, node, depth);
+ if (node->getBody()) {
+ out << "Loop Body\n";
+ node->getBody()->traverse(this);
+ } else
+ out << "No loop body\n";
+
+ if (node->getExpression()) {
+ OutputTreeText(sink, node, depth);
+ out << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getFlowOp()) {
+ case EOpKill: out << "Branch: Kill"; break;
+ case EOpBreak: out << "Branch: Break"; break;
+ case EOpContinue: out << "Branch: Continue"; break;
+ case EOpReturn: out << "Branch: Return"; break;
+ default: out << "Branch: Unknown Branch"; break;
+ }
+
+ if (node->getExpression()) {
+ out << " with expression\n";
+ ++depth;
+ node->getExpression()->traverse(this);
+ --depth;
+ } else
+ out << "\n";
+
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+void TIntermediate::outputTree(TIntermNode* root)
+{
+ if (root == 0)
+ return;
+
+ TOutputTraverser it(infoSink.info);
+
+ root->traverse(&it);
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/intermediate.h b/chromium/third_party/angle/src/compiler/translator/intermediate.h
new file mode 100644
index 00000000000..2fdde02e0f6
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/intermediate.h
@@ -0,0 +1,719 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders. This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree. There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef __INTERMEDIATE_H
+#define __INTERMEDIATE_H
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <algorithm>
+#include <queue>
+#include "compiler/translator/Common.h"
+#include "compiler/translator/Types.h"
+#include "compiler/translator/ConstantUnion.h"
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator {
+ EOpNull, // if in a node, should only mean a node is still being built
+ EOpSequence, // denotes a list of statements, or parameters, etc.
+ EOpFunctionCall,
+ EOpFunction, // For function definition
+ EOpParameters, // an aggregate listing the parameters to a function
+
+ EOpDeclaration,
+ EOpPrototype,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpLogicalNot,
+ EOpVectorLogicalNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ EOpConvIntToBool,
+ EOpConvUIntToBool,
+ EOpConvFloatToBool,
+ EOpConvBoolToFloat,
+ EOpConvIntToFloat,
+ EOpConvUIntToFloat,
+ EOpConvFloatToInt,
+ EOpConvBoolToInt,
+ EOpConvUIntToInt,
+ EOpConvIntToUInt,
+ EOpConvFloatToUInt,
+ EOpConvBoolToUInt,
+
+ //
+ // binary operations
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpEqual,
+ EOpNotEqual,
+ EOpVectorEqual,
+ EOpVectorNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+ EOpIndexDirectInterfaceBlock,
+
+ EOpVectorSwizzle,
+
+ //
+ // Built-in functions potentially mapped to operators
+ //
+
+ EOpRadians,
+ EOpDegrees,
+ EOpSin,
+ EOpCos,
+ EOpTan,
+ EOpAsin,
+ EOpAcos,
+ EOpAtan,
+
+ EOpPow,
+ EOpExp,
+ EOpLog,
+ EOpExp2,
+ EOpLog2,
+ EOpSqrt,
+ EOpInverseSqrt,
+
+ EOpAbs,
+ EOpSign,
+ EOpFloor,
+ EOpCeil,
+ EOpFract,
+ EOpMod,
+ EOpMin,
+ EOpMax,
+ EOpClamp,
+ EOpMix,
+ EOpStep,
+ EOpSmoothStep,
+
+ EOpLength,
+ EOpDistance,
+ EOpDot,
+ EOpCross,
+ EOpNormalize,
+ EOpFaceForward,
+ EOpReflect,
+ EOpRefract,
+
+ EOpDFdx, // Fragment only, OES_standard_derivatives extension
+ EOpDFdy, // Fragment only, OES_standard_derivatives extension
+ EOpFwidth, // Fragment only, OES_standard_derivatives extension
+
+ EOpMatrixTimesMatrix,
+
+ EOpAny,
+ EOpAll,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructors
+ //
+
+ EOpConstructInt,
+ EOpConstructUInt,
+ EOpConstructBool,
+ EOpConstructFloat,
+ EOpConstructVec2,
+ EOpConstructVec3,
+ EOpConstructVec4,
+ EOpConstructBVec2,
+ EOpConstructBVec3,
+ EOpConstructBVec4,
+ EOpConstructIVec2,
+ EOpConstructIVec3,
+ EOpConstructIVec4,
+ EOpConstructUVec2,
+ EOpConstructUVec3,
+ EOpConstructUVec4,
+ EOpConstructMat2,
+ EOpConstructMat3,
+ EOpConstructMat4,
+ EOpConstructStruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+ EOpDivAssign
+};
+
+extern const char* getOperatorString(TOperator op);
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermUnary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermTyped;
+class TIntermSymbol;
+class TIntermLoop;
+class TInfoSink;
+class TIntermRaw;
+
+//
+// Base class for the tree nodes
+//
+class TIntermNode {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermNode() {
+ // TODO: Move this to TSourceLoc constructor
+ // after getting rid of TPublicType.
+ line.first_file = line.last_file = 0;
+ line.first_line = line.last_line = 0;
+ }
+ virtual ~TIntermNode() { }
+
+ const TSourceLoc& getLine() const { return line; }
+ void setLine(const TSourceLoc& l) { line = l; }
+
+ virtual void traverse(TIntermTraverser*) = 0;
+ virtual TIntermTyped* getAsTyped() { return 0; }
+ virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
+ virtual TIntermAggregate* getAsAggregate() { return 0; }
+ virtual TIntermBinary* getAsBinaryNode() { return 0; }
+ virtual TIntermUnary* getAsUnaryNode() { return 0; }
+ virtual TIntermSelection* getAsSelectionNode() { return 0; }
+ virtual TIntermSymbol* getAsSymbolNode() { return 0; }
+ virtual TIntermLoop* getAsLoopNode() { return 0; }
+ virtual TIntermRaw* getAsRawNode() { return 0; }
+
+ // Replace a child node. Return true if |original| is a child
+ // node and it is replaced; otherwise, return false.
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement) = 0;
+
+ // For traversing a tree in no particular order, but using
+ // heap memory.
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const = 0;
+
+protected:
+ TSourceLoc line;
+};
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair {
+ TIntermNode* node1;
+ TIntermNode* node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode {
+public:
+ TIntermTyped(const TType& t) : type(t) { }
+ virtual TIntermTyped* getAsTyped() { return this; }
+
+ virtual bool hasSideEffects() const = 0;
+
+ void setType(const TType& t) { type = t; }
+ const TType& getType() const { return type; }
+ TType* getTypePointer() { return &type; }
+
+ TBasicType getBasicType() const { return type.getBasicType(); }
+ TQualifier getQualifier() const { return type.getQualifier(); }
+ TPrecision getPrecision() const { return type.getPrecision(); }
+ int getCols() const { return type.getCols(); }
+ int getRows() const { return type.getRows(); }
+ int getNominalSize() const { return type.getNominalSize(); }
+ int getSecondarySize() const { return type.getSecondarySize(); }
+
+ bool isInterfaceBlock() const { return type.isInterfaceBlock(); }
+ bool isMatrix() const { return type.isMatrix(); }
+ bool isArray() const { return type.isArray(); }
+ bool isVector() const { return type.isVector(); }
+ bool isScalar() const { return type.isScalar(); }
+ bool isScalarInt() const { return type.isScalarInt(); }
+ const char* getBasicString() const { return type.getBasicString(); }
+ const char* getQualifierString() const { return type.getQualifierString(); }
+ TString getCompleteString() const { return type.getCompleteString(); }
+
+ int getArraySize() const { return type.getArraySize(); }
+
+protected:
+ TType type;
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+enum TLoopType {
+ ELoopFor,
+ ELoopWhile,
+ ELoopDoWhile
+};
+
+class TIntermLoop : public TIntermNode {
+public:
+ TIntermLoop(TLoopType aType,
+ TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
+ TIntermNode* aBody) :
+ type(aType),
+ init(aInit),
+ cond(aCond),
+ expr(aExpr),
+ body(aBody),
+ unrollFlag(false) { }
+
+ virtual TIntermLoop* getAsLoopNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ TLoopType getType() const { return type; }
+ TIntermNode* getInit() { return init; }
+ TIntermTyped* getCondition() { return cond; }
+ TIntermTyped* getExpression() { return expr; }
+ TIntermNode* getBody() { return body; }
+
+ void setUnrollFlag(bool flag) { unrollFlag = flag; }
+ bool getUnrollFlag() { return unrollFlag; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TLoopType type;
+ TIntermNode* init; // for-loop initialization
+ TIntermTyped* cond; // loop exit condition
+ TIntermTyped* expr; // for-loop expression
+ TIntermNode* body; // loop body
+
+ bool unrollFlag; // Whether the loop should be unrolled or not.
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+ TIntermBranch(TOperator op, TIntermTyped* e) :
+ flowOp(op),
+ expression(e) { }
+
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ TOperator getFlowOp() { return flowOp; }
+ TIntermTyped* getExpression() { return expression; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TOperator flowOp;
+ TIntermTyped* expression; // non-zero except for "return exp;" statements
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped {
+public:
+ // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
+ // per process globalpoolallocator, then it causes increased memory usage per compile
+ // it is essential to use "symbol = sym" to assign to symbol
+ TIntermSymbol(int i, const TString& sym, const TType& t) :
+ TIntermTyped(t), id(i) { symbol = sym; }
+
+ virtual bool hasSideEffects() const { return false; }
+
+ int getId() const { return id; }
+ const TString& getSymbol() const { return symbol; }
+
+ void setId(int newId) { id = newId; }
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermSymbol* getAsSymbolNode() { return this; }
+ virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
+
+protected:
+ int id;
+ TString symbol;
+};
+
+// A Raw node stores raw code, that the translator will insert verbatim
+// into the output stream. Useful for transformation operations that make
+// complex code that might not fit naturally into the GLSL model.
+class TIntermRaw : public TIntermTyped {
+public:
+ TIntermRaw(const TType &t, const TString &rawTextIn)
+ : TIntermTyped(t), rawText(rawTextIn)
+ {}
+
+ virtual bool hasSideEffects() const { return false; }
+
+ TString getRawText() const { return rawText; }
+
+ virtual void traverse(TIntermTraverser*);
+
+ virtual TIntermRaw* getAsRawNode() { return this; }
+ virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
+
+protected:
+ TString rawText;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+ TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
+
+ virtual bool hasSideEffects() const { return false; }
+
+ ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
+
+ int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
+ unsigned int getUConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; }
+ float getFConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
+ bool getBConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
+
+ virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+
+ TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
+
+protected:
+ ConstantUnion *unionArrayPointer;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+ TOperator getOp() const { return op; }
+ void setOp(TOperator o) { op = o; }
+
+ bool isAssignment() const;
+ bool isConstructor() const;
+
+ virtual bool hasSideEffects() const { return isAssignment(); }
+
+protected:
+ TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
+ TIntermOperator(TOperator o, const TType& t) : TIntermTyped(t), op(o) {}
+ TOperator op;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+ TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
+
+ virtual TIntermBinary* getAsBinaryNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); }
+
+ void setLeft(TIntermTyped* n) { left = n; }
+ void setRight(TIntermTyped* n) { right = n; }
+ TIntermTyped* getLeft() const { return left; }
+ TIntermTyped* getRight() const { return right; }
+ bool promote(TInfoSink&);
+
+ void setAddIndexClamp() { addIndexClamp = true; }
+ bool getAddIndexClamp() { return addIndexClamp; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TIntermTyped* left;
+ TIntermTyped* right;
+
+ // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
+ bool addIndexClamp;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+ TIntermUnary(TOperator o, const TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
+ TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermUnary* getAsUnaryNode() { return this; }
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); }
+
+ void setOperand(TIntermTyped* o) { operand = o; }
+ TIntermTyped* getOperand() { return operand; }
+ bool promote(TInfoSink&);
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TIntermTyped* operand;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+typedef TVector<TIntermNode*> TIntermSequence;
+typedef TVector<int> TQualifierList;
+
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator {
+public:
+ TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { }
+ TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
+ ~TIntermAggregate() { }
+
+ virtual TIntermAggregate* getAsAggregate() { return this; }
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ // Conservatively assume function calls and other aggregate operators have side-effects
+ virtual bool hasSideEffects() const { return true; }
+
+ TIntermSequence& getSequence() { return sequence; }
+
+ void setName(const TString& n) { name = n; }
+ const TString& getName() const { return name; }
+
+ void setUserDefined() { userDefined = true; }
+ bool isUserDefined() const { return userDefined; }
+
+ void setOptimize(bool o) { optimize = o; }
+ bool getOptimize() { return optimize; }
+ void setDebug(bool d) { debug = d; }
+ bool getDebug() { return debug; }
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+ TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+ TIntermSequence sequence;
+ TString name;
+ bool userDefined; // used for user defined function names
+
+ bool optimize;
+ bool debug;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+//
+// For if tests. Simplified since there is no switch statement.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+ TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
+ TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+
+ virtual void traverse(TIntermTraverser*);
+ virtual bool replaceChildNode(
+ TIntermNode *original, TIntermNode *replacement);
+
+ // Conservatively assume selections have side-effects
+ virtual bool hasSideEffects() const { return true; }
+
+ bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
+ TIntermNode* getCondition() const { return condition; }
+ TIntermNode* getTrueBlock() const { return trueBlock; }
+ TIntermNode* getFalseBlock() const { return falseBlock; }
+ TIntermSelection* getAsSelectionNode() { return this; }
+
+ virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const;
+
+protected:
+ TIntermTyped* condition;
+ TIntermNode* trueBlock;
+ TIntermNode* falseBlock;
+};
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+//
+// For traversing the tree. User should derive from this,
+// put their traversal specific data in it, and then pass
+// it to a Traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+class TIntermTraverser
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
+ preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ rightToLeft(rightToLeft),
+ depth(0),
+ maxDepth(0) {}
+ virtual ~TIntermTraverser() {}
+
+ virtual void visitSymbol(TIntermSymbol*) {}
+ virtual void visitRaw(TIntermRaw*) {}
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
+ virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
+ virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
+ virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
+ virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
+
+ int getMaxDepth() const {return maxDepth;}
+
+ void incrementDepth(TIntermNode *current)
+ {
+ depth++;
+ maxDepth = std::max(maxDepth, depth);
+ path.push_back(current);
+ }
+
+ void decrementDepth()
+ {
+ depth--;
+ path.pop_back();
+ }
+
+ TIntermNode *getParentNode()
+ {
+ return path.size() == 0 ? NULL : path.back();
+ }
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ static TString hash(const TString& name, ShHashFunction64 hashFunction);
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+ const bool rightToLeft;
+
+protected:
+ int depth;
+ int maxDepth;
+
+ // All the nodes from root to the current node's parent during traversing.
+ TVector<TIntermNode *> path;
+};
+
+//
+// For traversing the tree, and computing max depth.
+// Takes a maximum depth limit to prevent stack overflow.
+//
+class TMaxDepthTraverser : public TIntermTraverser
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TMaxDepthTraverser(int depthLimit)
+ : TIntermTraverser(true, true, false, false),
+ depthLimit(depthLimit)
+ {}
+
+ virtual bool visitBinary(Visit visit, TIntermBinary*) { return depthCheck(); }
+ virtual bool visitUnary(Visit visit, TIntermUnary*) { return depthCheck(); }
+ virtual bool visitSelection(Visit visit, TIntermSelection*) { return depthCheck(); }
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*) { return depthCheck(); }
+ virtual bool visitLoop(Visit visit, TIntermLoop*) { return depthCheck(); }
+ virtual bool visitBranch(Visit visit, TIntermBranch*) { return depthCheck(); }
+
+protected:
+ int depthLimit;
+
+ bool depthCheck() const { return maxDepth < depthLimit; }
+};
+
+#endif // __INTERMEDIATE_H
diff --git a/chromium/third_party/angle/src/compiler/translator/length_limits.h b/chromium/third_party/angle/src/compiler/translator/length_limits.h
new file mode 100644
index 00000000000..df70ee5d84a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/length_limits.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2011-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// length_limits.h
+//
+
+#if !defined(__LENGTH_LIMITS_H)
+#define __LENGTH_LIMITS_H 1
+
+#include "GLSLANG/ShaderLang.h"
+
+// These constants are factored out from the rest of the headers to
+// make it easier to reference them from the compiler sources.
+
+size_t GetGlobalMaxTokenSize(ShShaderSpec spec);
+
+#endif // !(defined(__LENGTH_LIMITS_H)
diff --git a/chromium/third_party/angle/src/compiler/translator/localintermediate.h b/chromium/third_party/angle/src/compiler/translator/localintermediate.h
new file mode 100644
index 00000000000..125dcd989a2
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/localintermediate.h
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
+#define _LOCAL_INTERMEDIATE_INCLUDED_
+
+#include "compiler/translator/intermediate.h"
+
+struct TVectorFields {
+ int offsets[4];
+ int num;
+};
+
+//
+// Set of helper functions to help parse and build the tree.
+//
+class TInfoSink;
+class TIntermediate {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermediate(TInfoSink& i) : infoSink(i) { }
+
+ TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&);
+ TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+ TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
+ TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
+ TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
+ TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, const TSourceLoc&);
+ TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
+ TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
+ TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, const TSourceLoc&);
+ TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
+ TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
+ TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
+ TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, const TSourceLoc&);
+ TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+ bool parseConstTree(const TSourceLoc&, TIntermNode*, ConstantUnion*, TOperator, TType, bool singleConstantParam = false);
+ TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, const TSourceLoc&);
+ TIntermBranch* addBranch(TOperator, const TSourceLoc&);
+ TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
+ bool postProcess(TIntermNode*);
+ void remove(TIntermNode*);
+ void outputTree(TIntermNode*);
+
+private:
+ void operator=(TIntermediate&); // prevent assignments
+
+ TInfoSink& infoSink;
+};
+
+#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/chromium/third_party/angle/src/compiler/translator/osinclude.h b/chromium/third_party/angle/src/compiler/translator/osinclude.h
new file mode 100644
index 00000000000..c3063d624a8
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/osinclude.h
@@ -0,0 +1,66 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __OSINCLUDE_H
+#define __OSINCLUDE_H
+
+//
+// This file contains contains os-specific datatypes and
+// declares any os-specific functions.
+//
+
+#if defined(_WIN32) || defined(_WIN64)
+#define ANGLE_OS_WIN
+#elif defined(__APPLE__) || defined(__linux__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__sun) || defined(ANDROID) || \
+ defined(__GLIBC__) || defined(__GNU__) || \
+ defined(__QNX__)
+#define ANGLE_OS_POSIX
+#else
+#error Unsupported platform.
+#endif
+
+#if defined(ANGLE_OS_WIN)
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#elif defined(ANGLE_OS_POSIX)
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#endif // ANGLE_OS_WIN
+
+
+#include "compiler/translator/compilerdebug.h"
+
+//
+// Thread Local Storage Operations
+//
+#if defined(ANGLE_OS_WIN)
+typedef DWORD OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES)
+#elif defined(ANGLE_OS_POSIX)
+typedef pthread_key_t OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (static_cast<OS_TLSIndex>(-1))
+#endif // ANGLE_OS_WIN
+
+OS_TLSIndex OS_AllocTLSIndex();
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex);
+
+inline void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+ ASSERT(nIndex != OS_INVALID_TLS_INDEX);
+#if defined(ANGLE_OS_WIN)
+ return TlsGetValue(nIndex);
+#elif defined(ANGLE_OS_POSIX)
+ return pthread_getspecific(nIndex);
+#endif // ANGLE_OS_WIN
+}
+
+#endif // __OSINCLUDE_H
diff --git a/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp b/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp
new file mode 100644
index 00000000000..90a37574441
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// This file contains the posix specific functions
+//
+#include "compiler/translator/osinclude.h"
+
+#if !defined(ANGLE_OS_POSIX)
+#error Trying to build a posix specific file in a non-posix build.
+#endif
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ pthread_key_t pPoolIndex;
+
+ //
+ // Create global pool key.
+ //
+ if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return false;
+ }
+ else {
+ return pPoolIndex;
+ }
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (pthread_setspecific(nIndex, lpvValue) == 0)
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ //
+ // Delete the global pool key.
+ //
+ if (pthread_key_delete(nIndex) == 0)
+ return true;
+ else
+ return false;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp b/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp
new file mode 100644
index 00000000000..2cc5871b71d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/osinclude.h"
+//
+// This file contains contains the window's specific functions
+//
+
+#if !defined(ANGLE_OS_WIN)
+#error Trying to build a windows specific file in a non windows build.
+#endif
+
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ DWORD dwIndex = TlsAlloc();
+ if (dwIndex == TLS_OUT_OF_INDEXES) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return dwIndex;
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsSetValue(nIndex, lpvValue))
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsFree(nIndex))
+ return true;
+ else
+ return false;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/parseConst.cpp b/chromium/third_party/angle/src/compiler/translator/parseConst.cpp
new file mode 100644
index 00000000000..33617e53d9a
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/parseConst.cpp
@@ -0,0 +1,251 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ParseContext.h"
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TConstTraverser : public TIntermTraverser {
+public:
+ TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t)
+ : error(false),
+ index(0),
+ unionArray(cUnion),
+ type(t),
+ constructorType(constructType),
+ singleConstantParam(singleConstParam),
+ infoSink(sink),
+ size(0),
+ isDiagonalMatrixInit(false),
+ matrixCols(0),
+ matrixRows(0) {
+ }
+
+ bool error;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ size_t index;
+ ConstantUnion *unionArray;
+ TType type;
+ TOperator constructorType;
+ bool singleConstantParam;
+ TInfoSink& infoSink;
+ size_t size; // size of the constructor ( 4 for vec4)
+ bool isDiagonalMatrixInit;
+ int matrixCols; // columns of the matrix
+ int matrixRows; // rows of the matrix
+};
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TConstTraverser::visitSymbol(TIntermSymbol* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor");
+ return;
+
+}
+
+bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TQualifier qualifier = node->getType().getQualifier();
+
+ if (qualifier != EvqConst) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+ }
+
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor");
+
+ return false;
+}
+
+bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ if (!node->isConstructor() && node->getOp() != EOpComma) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+ }
+
+ if (node->getSequence().size() == 0) {
+ error = true;
+ return false;
+ }
+
+ bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
+ if (flag)
+ {
+ singleConstantParam = true;
+ constructorType = node->getOp();
+ size = node->getType().getObjectSize();
+
+ if (node->getType().isMatrix()) {
+ isDiagonalMatrixInit = true;
+ matrixCols = node->getType().getCols();
+ matrixRows = node->getType().getRows();
+ }
+ }
+
+ for (TIntermSequence::iterator p = node->getSequence().begin();
+ p != node->getSequence().end(); p++) {
+
+ if (node->getOp() == EOpComma)
+ index = 0;
+
+ (*p)->traverse(this);
+ }
+ if (flag)
+ {
+ singleConstantParam = false;
+ constructorType = EOpNull;
+ size = 0;
+ isDiagonalMatrixInit = false;
+ matrixCols = 0;
+ matrixRows = 0;
+ }
+ return false;
+}
+
+bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ if (!node->getUnionArrayPointer())
+ {
+ // The constant was not initialized, this should already have been logged
+ assert(infoSink.info.size() != 0);
+ return;
+ }
+
+ ConstantUnion* leftUnionArray = unionArray;
+ size_t instanceSize = type.getObjectSize();
+
+ if (index >= instanceSize)
+ return;
+
+ if (!singleConstantParam) {
+ size_t objectSize = node->getType().getObjectSize();
+
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ for (size_t i=0; i < objectSize; i++) {
+ if (index >= instanceSize)
+ return;
+ leftUnionArray[index] = rightUnionArray[i];
+
+ (index)++;
+ }
+ } else {
+ size_t totalSize = index + size;
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ if (!isDiagonalMatrixInit) {
+ int count = 0;
+ for (size_t i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+
+ leftUnionArray[i] = rightUnionArray[count];
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ }
+ else
+ {
+ // for matrix diagonal constructors from a single scalar
+ for (int i = 0, col = 0; col < matrixCols; col++)
+ {
+ for (int row = 0; row < matrixRows; row++, i++)
+ {
+ if (col == row)
+ {
+ leftUnionArray[i] = rightUnionArray[0];
+ }
+ else
+ {
+ leftUnionArray[i].setFConst(0.0f);
+ }
+
+ (index)++;
+ }
+ }
+ }
+ }
+}
+
+bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam)
+{
+ if (root == 0)
+ return false;
+
+ TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t);
+
+ root->traverse(&it);
+ if (it.error)
+ return true;
+ else
+ return false;
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp
new file mode 100644
index 00000000000..48d44c72d17
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp
@@ -0,0 +1,136 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/depgraph/DependencyGraphOutput.h"
+#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
+
+RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
+ : mSink(sink)
+ , mNumErrors(0)
+{
+ // Sampling ops found only in fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
+ mSamplingOps.insert("textureCube(sC1;vf3;f1;");
+ // Sampling ops found in both vertex and fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;");
+ mSamplingOps.insert("textureCube(sC1;vf3;");
+ // Sampling ops provided by OES_EGL_image_external.
+ mSamplingOps.insert("texture2D(1;vf2;");
+ mSamplingOps.insert("texture2DProj(1;vf3;");
+ mSamplingOps.insert("texture2DProj(1;vf4;");
+ // Sampling ops provided by ARB_texture_rectangle.
+ mSamplingOps.insert("texture2DRect(1;vf2;");
+ mSamplingOps.insert("texture2DRectProj(1;vf3;");
+ mSamplingOps.insert("texture2DRectProj(1;vf4;");
+ // Sampling ops provided by EXT_shader_texture_lod.
+ mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;");
+ mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;");
+ mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;");
+ mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;");
+ mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;");
+ mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;");
+ mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;");
+ mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;");
+}
+
+// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
+// can vary based on the value of the input arguments. If so, we should restrict those as well.
+void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
+{
+ mNumErrors = 0;
+
+ // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
+ // so we generate errors for them.
+ validateUserDefinedFunctionCallUsage(graph);
+
+ // Starting from each sampler, traverse the dependency graph and generate an error each time we
+ // hit a node where sampler dependent values are not allowed.
+ for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
+ iter != graph.endSamplerSymbols();
+ ++iter)
+ {
+ TGraphSymbol* samplerSymbol = *iter;
+ clearVisited();
+ samplerSymbol->traverse(this);
+ }
+}
+
+void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
+{
+ for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+ iter != graph.endUserDefinedFunctionCalls();
+ ++iter)
+ {
+ TGraphFunctionCall* functionCall = *iter;
+ beginError(functionCall->getIntermFunctionCall());
+ mSink << "A call to a user defined function is not permitted.\n";
+ }
+}
+
+void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
+{
+ ++mNumErrors;
+ mSink.prefix(EPrefixError);
+ mSink.location(node->getLine());
+}
+
+bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
+{
+ return !intermFunctionCall->isUserDefined() &&
+ mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
+}
+
+void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
+{
+ // Texture cache access time might leak sensitive information.
+ // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
+ // sampling operation.
+ if (isSamplingOp(parameter->getIntermFunctionCall())) {
+ switch (parameter->getArgumentNumber()) {
+ case 1:
+ // Second argument (coord)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " coordinate argument of a sampling operation.\n";
+ break;
+ case 2:
+ // Third argument (bias)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " bias argument of a sampling operation.\n";
+ break;
+ default:
+ // First argument (sampler)
+ break;
+ }
+ }
+}
+
+void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
+{
+ beginError(selection->getIntermSelection());
+ mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
+{
+ beginError(loop->getIntermLoop());
+ mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ beginError(logicalOp->getIntermLogicalOp());
+ mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
+ << logicalOp->getOpString()
+ << " operator.\n";
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h
new file mode 100644
index 00000000000..e77d8c21cbc
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/depgraph/DependencyGraph.h"
+
+class TInfoSinkBase;
+
+class RestrictFragmentShaderTiming : TDependencyGraphTraverser {
+public:
+ RestrictFragmentShaderTiming(TInfoSinkBase& sink);
+ void enforceRestrictions(const TDependencyGraph& graph);
+ int numErrors() const { return mNumErrors; }
+
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+private:
+ void beginError(const TIntermNode* node);
+ void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph);
+ bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const;
+
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+
+ typedef std::set<TString> StringSet;
+ StringSet mSamplingOps;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp
new file mode 100644
index 00000000000..7c1208a2986
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
+
+void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node)
+{
+ if (IsSampler(node->getBasicType())) {
+ ++mNumErrors;
+ mSink.message(EPrefixError,
+ node->getLine(),
+ "Samplers are not permitted in vertex shaders.\n");
+ }
+}
diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h
new file mode 100644
index 00000000000..d461fbdbfea
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+
+#include "compiler/translator/intermediate.h"
+#include "compiler/translator/InfoSink.h"
+
+class TInfoSinkBase;
+
+class RestrictVertexShaderTiming : public TIntermTraverser {
+public:
+ RestrictVertexShaderTiming(TInfoSinkBase& sink)
+ : TIntermTraverser(true, false, false)
+ , mSink(sink)
+ , mNumErrors(0) {}
+
+ void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
+ int numErrors() { return mNumErrors; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+private:
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
diff --git a/chromium/third_party/angle/src/compiler/translator/util.cpp b/chromium/third_party/angle/src/compiler/translator/util.cpp
new file mode 100644
index 00000000000..077bdcc48b8
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/util.cpp
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/util.h"
+
+#include <limits>
+
+#include "compiler/preprocessor/numeric_lex.h"
+
+bool atof_clamp(const char *str, float *value)
+{
+ bool success = pp::numeric_lex_float(str, value);
+ if (!success)
+ *value = std::numeric_limits<float>::max();
+ return success;
+}
+
+bool atoi_clamp(const char *str, int *value)
+{
+ bool success = pp::numeric_lex_int(str, value);
+ if (!success)
+ *value = std::numeric_limits<int>::max();
+ return success;
+}
+
diff --git a/chromium/third_party/angle/src/compiler/translator/util.h b/chromium/third_party/angle/src/compiler/translator/util.h
new file mode 100644
index 00000000000..dc69f39060d
--- /dev/null
+++ b/chromium/third_party/angle/src/compiler/translator/util.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_UTIL_H
+#define COMPILER_UTIL_H
+
+// atof_clamp is like atof but
+// 1. it forces C locale, i.e. forcing '.' as decimal point.
+// 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
+// Return false if overflow happens.
+extern bool atof_clamp(const char *str, float *value);
+
+// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// Return false if overflow happens.
+extern bool atoi_clamp(const char *str, int *value);
+
+#endif // COMPILER_UTIL_H