blob: e9b392e7e2d1867e39ee6e403051a34941f45e19 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madill6b9cb252013-10-17 10:45:47 -04007#include "compiler/translator/ParseContext.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009#include <stdarg.h>
apatrick@chromium.org8187fa82010-06-15 22:09:28 +000010#include <stdio.h>
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011
daniel@transgaming.comb401a922012-10-26 18:58:24 +000012#include "compiler/preprocessor/SourceLocation.h"
Olli Etuahoac5274d2015-02-20 10:19:08 +020013#include "compiler/translator/glslang.h"
14#include "compiler/translator/ValidateSwitch.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000015
alokp@chromium.org8b851c62012-06-15 16:25:11 +000016///////////////////////////////////////////////////////////////////////
17//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018// Sub- vector and matrix fields
19//
20////////////////////////////////////////////////////////////////////////
21
22//
23// Look at a '.' field selector string and change it into offsets
24// for a vector.
25//
Jamie Madill075edd82013-07-08 13:30:19 -040026bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000028 fields.num = (int) compString.size();
29 if (fields.num > 4) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000030 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000031 return false;
32 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000034 enum {
35 exyzw,
36 ergba,
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000037 estpq
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000038 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000039
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000040 for (int i = 0; i < fields.num; ++i) {
41 switch (compString[i]) {
42 case 'x':
43 fields.offsets[i] = 0;
44 fieldSet[i] = exyzw;
45 break;
46 case 'r':
47 fields.offsets[i] = 0;
48 fieldSet[i] = ergba;
49 break;
50 case 's':
51 fields.offsets[i] = 0;
52 fieldSet[i] = estpq;
53 break;
54 case 'y':
55 fields.offsets[i] = 1;
56 fieldSet[i] = exyzw;
57 break;
58 case 'g':
59 fields.offsets[i] = 1;
60 fieldSet[i] = ergba;
61 break;
62 case 't':
63 fields.offsets[i] = 1;
64 fieldSet[i] = estpq;
65 break;
66 case 'z':
67 fields.offsets[i] = 2;
68 fieldSet[i] = exyzw;
69 break;
70 case 'b':
71 fields.offsets[i] = 2;
72 fieldSet[i] = ergba;
73 break;
74 case 'p':
75 fields.offsets[i] = 2;
76 fieldSet[i] = estpq;
77 break;
78
79 case 'w':
80 fields.offsets[i] = 3;
81 fieldSet[i] = exyzw;
82 break;
83 case 'a':
84 fields.offsets[i] = 3;
85 fieldSet[i] = ergba;
86 break;
87 case 'q':
88 fields.offsets[i] = 3;
89 fieldSet[i] = estpq;
90 break;
91 default:
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000092 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000093 return false;
94 }
95 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000097 for (int i = 0; i < fields.num; ++i) {
98 if (fields.offsets[i] >= vecSize) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000099 error(line, "vector field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000100 return false;
101 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000103 if (i > 0) {
104 if (fieldSet[i] != fieldSet[i-1]) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000105 error(line, "illegal - vector component fields not from the same set", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000106 return false;
107 }
108 }
109 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000111 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112}
113
114
115//
116// Look at a '.' field selector string and change it into offsets
117// for a matrix.
118//
Jamie Madill075edd82013-07-08 13:30:19 -0400119bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000121 fields.wholeRow = false;
122 fields.wholeCol = false;
123 fields.row = -1;
124 fields.col = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000126 if (compString.size() != 2) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000127 error(line, "illegal length of matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000128 return false;
129 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000131 if (compString[0] == '_') {
132 if (compString[1] < '0' || compString[1] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000133 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000134 return false;
135 }
136 fields.wholeCol = true;
137 fields.col = compString[1] - '0';
138 } else if (compString[1] == '_') {
139 if (compString[0] < '0' || compString[0] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000140 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000141 return false;
142 }
143 fields.wholeRow = true;
144 fields.row = compString[0] - '0';
145 } else {
146 if (compString[0] < '0' || compString[0] > '3' ||
147 compString[1] < '0' || compString[1] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000148 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000149 return false;
150 }
151 fields.row = compString[0] - '0';
152 fields.col = compString[1] - '0';
153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000155 if (fields.row >= matRows || fields.col >= matCols) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000156 error(line, "matrix field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000157 return false;
158 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000160 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161}
162
163///////////////////////////////////////////////////////////////////////
164//
165// Errors
166//
167////////////////////////////////////////////////////////////////////////
168
169//
170// Track whether errors have occurred.
171//
172void TParseContext::recover()
173{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174}
175
176//
177// Used by flex/bison to output all syntax and parsing errors.
178//
Jamie Madill075edd82013-07-08 13:30:19 -0400179void TParseContext::error(const TSourceLoc& loc,
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000180 const char* reason, const char* token,
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000181 const char* extraInfo)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000183 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400184 srcLoc.file = loc.first_file;
185 srcLoc.line = loc.first_line;
Shannon Woods7f2d7942013-11-19 15:07:58 -0500186 diagnostics.writeInfo(pp::Diagnostics::PP_ERROR,
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000187 srcLoc, reason, token, extraInfo);
alokp@chromium.orgff42c632010-05-10 15:14:30 +0000188
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
Jamie Madill075edd82013-07-08 13:30:19 -0400191void TParseContext::warning(const TSourceLoc& loc,
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000192 const char* reason, const char* token,
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000193 const char* extraInfo) {
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000194 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400195 srcLoc.file = loc.first_file;
196 srcLoc.line = loc.first_line;
Shannon Woods7f2d7942013-11-19 15:07:58 -0500197 diagnostics.writeInfo(pp::Diagnostics::PP_WARNING,
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000198 srcLoc, reason, token, extraInfo);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000199}
200
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000201void TParseContext::trace(const char* str)
202{
203 diagnostics.writeDebug(str);
204}
205
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206//
207// Same error message for all places assignments don't work.
208//
Jamie Madill075edd82013-07-08 13:30:19 -0400209void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000211 std::stringstream extraInfoStream;
212 extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
213 std::string extraInfo = extraInfoStream.str();
214 error(line, "", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215}
216
217//
218// Same error message for all places unary operations don't work.
219//
Jamie Madill075edd82013-07-08 13:30:19 -0400220void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000222 std::stringstream extraInfoStream;
223 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
224 << " (or there is no acceptable conversion)";
225 std::string extraInfo = extraInfoStream.str();
226 error(line, " wrong operand type", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227}
228
229//
230// Same error message for all binary operations don't work.
231//
Jamie Madill075edd82013-07-08 13:30:19 -0400232void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000234 std::stringstream extraInfoStream;
235 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
236 << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
237 std::string extraInfo = extraInfoStream.str();
238 error(line, " wrong operand types ", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239}
240
Jamie Madill075edd82013-07-08 13:30:19 -0400241bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000242 if (!checksPrecisionErrors)
243 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000244 switch( type ){
245 case EbtFloat:
246 if( precision == EbpUndefined ){
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000247 error( line, "No precision specified for (float)", "" );
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000248 return true;
249 }
250 break;
251 case EbtInt:
252 if( precision == EbpUndefined ){
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000253 error( line, "No precision specified (int)", "" );
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000254 return true;
255 }
256 break;
daniel@transgaming.com0eb64c32011-03-15 18:23:51 +0000257 default:
258 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000259 }
260 return false;
261}
262
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000263//
264// Both test and if necessary, spit out an error, to see if the node is really
265// an l-value that can be operated on this way.
266//
267// Returns true if the was an error.
268//
Jamie Madill075edd82013-07-08 13:30:19 -0400269bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000271 TIntermSymbol* symNode = node->getAsSymbolNode();
272 TIntermBinary* binaryNode = node->getAsBinaryNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000274 if (binaryNode) {
275 bool errorReturn;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000277 switch(binaryNode->getOp()) {
278 case EOpIndexDirect:
279 case EOpIndexIndirect:
280 case EOpIndexDirectStruct:
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000281 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000282 return lValueErrorCheck(line, op, binaryNode->getLeft());
283 case EOpVectorSwizzle:
284 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
285 if (!errorReturn) {
286 int offset[4] = {0,0,0,0};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000288 TIntermTyped* rightNode = binaryNode->getRight();
289 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700290
291 for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
292 p != aggrNode->getSequence()->end(); p++) {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000293 int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700294 offset[value]++;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000295 if (offset[value] > 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000296 error(line, " l-value of swizzle cannot have duplicate components", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000298 return true;
299 }
300 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700301 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000303 return errorReturn;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700304 default:
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000305 break;
306 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000307 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000309 return true;
310 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311
312
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000313 const char* symbol = 0;
314 if (symNode != 0)
315 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000317 const char* message = 0;
318 switch (node->getQualifier()) {
319 case EvqConst: message = "can't modify a const"; break;
320 case EvqConstReadOnly: message = "can't modify a const"; break;
321 case EvqAttribute: message = "can't modify an attribute"; break;
Jamie Madill19571812013-08-12 15:26:34 -0700322 case EvqFragmentIn: message = "can't modify an input"; break;
323 case EvqVertexIn: message = "can't modify an input"; break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000324 case EvqUniform: message = "can't modify a uniform"; break;
325 case EvqVaryingIn: message = "can't modify a varying"; break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000326 case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
327 case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
328 case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
329 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000331 //
332 // Type that can't be written to?
333 //
Nicolas Capens344e7142013-06-24 15:39:21 -0400334 if (node->getBasicType() == EbtVoid) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000335 message = "can't modify void";
Nicolas Capens344e7142013-06-24 15:39:21 -0400336 }
337 if (IsSampler(node->getBasicType())) {
338 message = "can't modify a sampler";
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000339 }
340 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000342 if (message == 0 && binaryNode == 0 && symNode == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000343 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000345 return true;
346 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347
348
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000349 //
350 // Everything else is okay, no error.
351 //
352 if (message == 0)
353 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000355 //
356 // If we get here, we have an error and a message.
357 //
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000358 if (symNode) {
359 std::stringstream extraInfoStream;
360 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
361 std::string extraInfo = extraInfoStream.str();
362 error(line, " l-value required", op, extraInfo.c_str());
363 }
364 else {
365 std::stringstream extraInfoStream;
366 extraInfoStream << "(" << message << ")";
367 std::string extraInfo = extraInfoStream.str();
368 error(line, " l-value required", op, extraInfo.c_str());
369 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000371 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372}
373
374//
375// Both test, and if necessary spit out an error, to see if the node is really
376// a constant.
377//
378// Returns true if the was an error.
379//
380bool TParseContext::constErrorCheck(TIntermTyped* node)
381{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000382 if (node->getQualifier() == EvqConst)
383 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000385 error(node->getLine(), "constant expression required", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000387 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388}
389
390//
391// Both test, and if necessary spit out an error, to see if the node is really
392// an integer.
393//
394// Returns true if the was an error.
395//
396bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
397{
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000398 if (node->isScalarInt())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000399 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000401 error(node->getLine(), "integer expression required", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000403 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000404}
405
406//
407// Both test, and if necessary spit out an error, to see if we are currently
408// globally scoped.
409//
410// Returns true if the was an error.
411//
Jamie Madill075edd82013-07-08 13:30:19 -0400412bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000414 if (global)
415 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000417 error(line, "only allowed at global scope", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000419 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420}
421
422//
423// For now, keep it simple: if it starts "gl_", it's reserved, independent
424// of scope. Except, if the symbol table is at the built-in push-level,
425// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000426// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
427// webgl shader.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428//
429// Returns true if there was an error.
430//
Jamie Madill075edd82013-07-08 13:30:19 -0400431bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432{
alokp@chromium.org613ef312010-07-21 18:54:22 +0000433 static const char* reservedErrMsg = "reserved built-in name";
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000434 if (!symbolTable.atBuiltInLevel()) {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000435 if (identifier.compare(0, 3, "gl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000436 error(line, reservedErrMsg, "gl_");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000437 return true;
438 }
Jamie Madill5508f392014-02-20 13:31:36 -0500439 if (IsWebGLBasedSpec(shaderSpec)) {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000440 if (identifier.compare(0, 6, "webgl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000441 error(line, reservedErrMsg, "webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000442 return true;
443 }
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000444 if (identifier.compare(0, 7, "_webgl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000445 error(line, reservedErrMsg, "_webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000446 return true;
447 }
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000448 if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000449 error(line, reservedErrMsg, "css_");
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000450 return true;
451 }
alokp@chromium.org613ef312010-07-21 18:54:22 +0000452 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000453 if (identifier.find("__") != TString::npos) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000454 error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
daniel@transgaming.combeadd5d2012-04-12 02:35:31 +0000455 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000456 }
457 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000459 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460}
461
462//
463// Make sure there is enough data provided to the constructor to build
464// something of the type of the constructor. Also returns the type of
465// the constructor.
466//
467// Returns true if there was an error in construction.
468//
Jamie Madill075edd82013-07-08 13:30:19 -0400469bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000471 *type = function.getReturnType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000473 bool constructingMatrix = false;
474 switch(op) {
475 case EOpConstructMat2:
476 case EOpConstructMat3:
477 case EOpConstructMat4:
478 constructingMatrix = true;
479 break;
480 default:
481 break;
482 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000484 //
485 // Note: It's okay to have too many components available, but not okay to have unused
486 // arguments. 'full' will go to true when enough args have been seen. If we loop
487 // again, there is an extra argument, so 'overfull' will become true.
488 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489
Jamie Madill94bf7f22013-07-08 13:31:15 -0400490 size_t size = 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000491 bool constType = true;
492 bool full = false;
493 bool overFull = false;
494 bool matrixInMatrix = false;
495 bool arrayArg = false;
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000496 for (size_t i = 0; i < function.getParamCount(); ++i) {
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000497 const TParameter& param = function.getParam(i);
498 size += param.type->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000499
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000500 if (constructingMatrix && param.type->isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000501 matrixInMatrix = true;
502 if (full)
503 overFull = true;
504 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
505 full = true;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000506 if (param.type->getQualifier() != EvqConst)
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000507 constType = false;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000508 if (param.type->isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000509 arrayArg = true;
510 }
511
512 if (constType)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000513 type->setQualifier(EvqConst);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514
shannon.woods@transgaming.com18bd2ec2013-02-28 23:19:46 +0000515 if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000516 error(line, "array constructor needs one argument per array element", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000517 return true;
518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000520 if (arrayArg && op != EOpConstructStruct) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000521 error(line, "constructing from a non-dereferenced array", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000522 return true;
523 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000525 if (matrixInMatrix && !type->isArray()) {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000526 if (function.getParamCount() != 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000527 error(line, "constructing matrix from matrix can only take one argument", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000528 return true;
529 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000530 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000532 if (overFull) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000533 error(line, "too many arguments", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000534 return true;
535 }
536
Brendan Longeaa84062013-12-08 18:26:50 +0100537 if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000538 error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000539 return true;
540 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541
daniel@transgaming.com67d72522011-11-29 17:23:51 +0000542 if (!type->isMatrix() || !matrixInMatrix) {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000543 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
544 (op == EOpConstructStruct && size < type->getObjectSize())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000545 error(line, "not enough data provided for construction", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000546 return true;
547 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000548 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549
daniel@transgaming.com0b53fc02011-03-09 15:12:12 +0000550 TIntermTyped *typed = node ? node->getAsTyped() : 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000551 if (typed == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000552 error(line, "constructor argument does not have a type", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000553 return true;
554 }
555 if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000556 error(line, "cannot convert a sampler", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000557 return true;
558 }
559 if (typed->getBasicType() == EbtVoid) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000560 error(line, "cannot convert a void", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000561 return true;
562 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000563
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000564 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565}
566
567// This function checks to see if a void variable has been declared and raise an error message for such a case
568//
569// returns true in case of an error
570//
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300571bool TParseContext::voidErrorCheck(const TSourceLoc &line, const TString &identifier, const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300573 if (type == EbtVoid)
574 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000575 error(line, "illegal use of type 'void'", identifier.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000576 return true;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300577 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000579 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580}
581
582// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
583//
584// returns true in case of an error
585//
Jamie Madill075edd82013-07-08 13:30:19 -0400586bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000587{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000588 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000589 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000590 return true;
591 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000592
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000593 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594}
595
596// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
597//
598// returns true in case of an error
599//
Jamie Madill075edd82013-07-08 13:30:19 -0400600bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601{
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000602 if (pType.type != EbtBool || pType.isAggregate()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000603 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000604 return true;
605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000607 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608}
609
Jamie Madill075edd82013-07-08 13:30:19 -0400610bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000612 if (pType.type == EbtStruct) {
613 if (containsSampler(*pType.userDef)) {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000614 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000615
616 return true;
617 }
618
619 return false;
620 } else if (IsSampler(pType.type)) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000621 error(line, reason, getBasicString(pType.type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000623 return true;
624 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000625
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000626 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000627}
628
Jamie Madill075edd82013-07-08 13:30:19 -0400629bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400630{
631 if (pType.layoutQualifier.location != -1)
632 {
633 error(line, "location must only be specified for a single input or output variable", "location");
634 return true;
635 }
636
637 return false;
638}
639
Jamie Madill075edd82013-07-08 13:30:19 -0400640bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000642 if ((qualifier == EvqOut || qualifier == EvqInOut) &&
643 type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000644 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000645 return true;
646 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000648 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649}
650
651bool TParseContext::containsSampler(TType& type)
652{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000653 if (IsSampler(type.getBasicType()))
654 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000655
Jamie Madill98493dd2013-07-08 14:39:03 -0400656 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
657 const TFieldList& fields = type.getStruct()->fields();
658 for (unsigned int i = 0; i < fields.size(); ++i) {
659 if (containsSampler(*fields[i]->type()))
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000660 return true;
661 }
662 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000664 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665}
666
667//
668// Do size checking for an array type's size.
669//
670// Returns true if there was an error.
671//
Jamie Madill075edd82013-07-08 13:30:19 -0400672bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000674 TIntermConstantUnion* constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000675
676 if (constant == 0 || !constant->isScalarInt())
677 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000678 error(line, "array size must be a constant integer expression", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000679 return true;
680 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000681
Nicolas Capens906744a2014-06-06 15:18:07 -0400682 unsigned int unsignedSize = 0;
683
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000684 if (constant->getBasicType() == EbtUInt)
685 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400686 unsignedSize = constant->getUConst(0);
687 size = static_cast<int>(unsignedSize);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000688 }
689 else
690 {
691 size = constant->getIConst(0);
692
Nicolas Capens906744a2014-06-06 15:18:07 -0400693 if (size < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000694 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400695 error(line, "array size must be non-negative", "");
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000696 size = 1;
697 return true;
698 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400699
700 unsignedSize = static_cast<unsigned int>(size);
701 }
702
703 if (size == 0)
704 {
705 error(line, "array size must be greater than zero", "");
706 size = 1;
707 return true;
708 }
709
710 // The size of arrays is restricted here to prevent issues further down the
711 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
712 // 4096 registers so this should be reasonable even for aggressively optimizable code.
713 const unsigned int sizeLimit = 65536;
714
715 if (unsignedSize > sizeLimit)
716 {
717 error(line, "array size too large", "");
718 size = 1;
719 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000720 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000721
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000722 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723}
724
725//
726// See if this qualifier can be an array.
727//
728// Returns true if there is an error.
729//
Olli Etuaho3739d232015-04-08 12:23:44 +0300730bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731{
Olli Etuaho3739d232015-04-08 12:23:44 +0300732 if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) ||
733 (type.qualifier == EvqConst && shaderVersion < 300))
734 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000735 error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000736 return true;
737 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000739 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740}
741
742//
743// See if this type can be an array.
744//
745// Returns true if there is an error.
746//
Jamie Madill075edd82013-07-08 13:30:19 -0400747bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000748{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000749 //
750 // Can the type be an array?
751 //
752 if (type.array) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000753 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000754 return true;
755 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000757 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000758}
759
760//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761// Enforce non-initializer type/qualifier rules.
762//
763// Returns true if there was an error.
764//
Olli Etuaho3739d232015-04-08 12:23:44 +0300765bool TParseContext::nonInitConstErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766{
Olli Etuaho3739d232015-04-08 12:23:44 +0300767 ASSERT(type != nullptr);
768 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000769 {
770 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +0300771 type->qualifier = EvqTemporary;
772
773 // Generate informative error messages for ESSL1.
774 // In ESSL3 arrays and structures containing arrays can be constant.
775 if (shaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000776 {
777 error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
778 }
779 else
780 {
781 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
782 }
783
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000784 return true;
785 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000786 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000787}
788
Olli Etuaho2935c582015-04-08 14:32:06 +0300789// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790// and update the symbol table.
791//
Olli Etuaho2935c582015-04-08 14:32:06 +0300792// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000793//
Olli Etuaho2935c582015-04-08 14:32:06 +0300794bool TParseContext::declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type,
795 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000796{
Olli Etuaho2935c582015-04-08 14:32:06 +0300797 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798
Olli Etuaho2935c582015-04-08 14:32:06 +0300799 bool needsReservedErrorCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000800
Olli Etuaho2935c582015-04-08 14:32:06 +0300801 // gl_LastFragData may be redeclared with a new precision qualifier
802 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
803 {
804 const TVariable *maxDrawBuffers =
805 static_cast<const TVariable *>(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion));
806 if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst())
807 {
808 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, shaderVersion))
809 {
810 needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
811 }
812 }
813 else
814 {
815 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers", identifier.c_str());
816 return false;
817 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000818 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000819
Olli Etuaho2935c582015-04-08 14:32:06 +0300820 if (needsReservedErrorCheck && reservedErrorCheck(line, identifier))
821 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000822
Olli Etuaho2935c582015-04-08 14:32:06 +0300823 (*variable) = new TVariable(&identifier, type);
824 if (!symbolTable.declare(*variable))
825 {
826 error(line, "redefinition", identifier.c_str());
827 delete (*variable);
828 (*variable) = nullptr;
829 return false;
830 }
831
832 if (voidErrorCheck(line, identifier, type.getBasicType()))
833 return false;
834
835 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836}
837
Jamie Madill075edd82013-07-08 13:30:19 -0400838bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000839{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000840 if (qualifier != EvqConst && qualifier != EvqTemporary) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000841 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000842 return true;
843 }
844 if (qualifier == EvqConst && paramQualifier != EvqIn) {
845 error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
846 return true;
847 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000848
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000849 if (qualifier == EvqConst)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000850 type->setQualifier(EvqConstReadOnly);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000851 else
alokp@chromium.org58e54292010-08-24 21:40:03 +0000852 type->setQualifier(paramQualifier);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000853
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000854 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000855}
856
Jamie Madill075edd82013-07-08 13:30:19 -0400857bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000858{
alokp@chromium.org73bc2982012-06-19 18:48:05 +0000859 const TExtensionBehavior& extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000860 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
861 if (iter == extBehavior.end()) {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000862 error(line, "extension", extension.c_str(), "is not supported");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000863 return true;
864 }
zmo@google.comf5450912011-09-09 01:37:19 +0000865 // In GLSL ES, an extension's default behavior is "disable".
866 if (iter->second == EBhDisable || iter->second == EBhUndefined) {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000867 error(line, "extension", extension.c_str(), "is disabled");
868 return true;
869 }
870 if (iter->second == EBhWarn) {
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000871 warning(line, "extension", extension.c_str(), "is being used");
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000872 return false;
873 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000875 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000876}
877
Olli Etuahofa33d582015-04-09 14:33:12 +0300878// These checks are common for all declarations starting a declarator list, and declarators that follow an empty
879// declaration.
880//
881bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc &identifierLocation)
Jamie Madilla5efff92013-06-06 11:56:47 -0400882{
Olli Etuahofa33d582015-04-09 14:33:12 +0300883 switch (publicType.qualifier)
884 {
885 case EvqVaryingIn:
886 case EvqVaryingOut:
887 case EvqAttribute:
888 case EvqVertexIn:
889 case EvqFragmentOut:
890 if (publicType.type == EbtStruct)
891 {
892 error(identifierLocation, "cannot be used with a structure",
893 getQualifierString(publicType.qualifier));
894 return true;
895 }
896
897 default: break;
898 }
899
900 if (publicType.qualifier != EvqUniform && samplerErrorCheck(identifierLocation, publicType,
901 "samplers must be uniform"))
902 {
Jamie Madilla5efff92013-06-06 11:56:47 -0400903 return true;
Olli Etuahofa33d582015-04-09 14:33:12 +0300904 }
Jamie Madilla5efff92013-06-06 11:56:47 -0400905
906 // check for layout qualifier issues
907 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
908
909 if (layoutQualifier.matrixPacking != EmpUnspecified)
910 {
Olli Etuahofa33d582015-04-09 14:33:12 +0300911 error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking),
912 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -0400913 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400914 }
915
916 if (layoutQualifier.blockStorage != EbsUnspecified)
917 {
Olli Etuahofa33d582015-04-09 14:33:12 +0300918 error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage),
919 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -0400920 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400921 }
922
Olli Etuahofa33d582015-04-09 14:33:12 +0300923 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut &&
924 layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -0400925 {
Jamie Madill51a53c72013-06-19 09:24:43 -0400926 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400927 }
928
929 return false;
930}
931
Jamie Madill075edd82013-07-08 13:30:19 -0400932bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier)
Jamie Madilla5efff92013-06-06 11:56:47 -0400933{
934 if (layoutQualifier.location != -1)
935 {
936 error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
937 return true;
938 }
939
940 return false;
941}
942
Olli Etuahob6e07a62015-02-16 12:22:10 +0200943bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate)
944{
945 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
946 {
947 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
948 if (qual == EvqOut || qual == EvqInOut)
949 {
950 TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped();
951 if (lValueErrorCheck(node->getLine(), "assign", node))
952 {
953 error(node->getLine(),
954 "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
955 recover();
956 return true;
957 }
958 }
959 }
960 return false;
961}
962
zmo@google.com09c323a2011-08-12 18:22:25 +0000963bool TParseContext::supportsExtension(const char* extension)
964{
alokp@chromium.org73bc2982012-06-19 18:48:05 +0000965 const TExtensionBehavior& extbehavior = extensionBehavior();
966 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
967 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000968}
969
Jamie Madill5d287f52013-07-12 15:38:19 -0400970bool TParseContext::isExtensionEnabled(const char* extension) const
971{
972 const TExtensionBehavior& extbehavior = extensionBehavior();
Shannon Woodsa49a9bf2013-08-02 17:23:14 -0400973 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
Jamie Madill5d287f52013-07-12 15:38:19 -0400974
975 if (iter == extbehavior.end())
976 {
977 return false;
978 }
979
980 return (iter->second == EBhEnable || iter->second == EBhRequire);
981}
982
Jamie Madill075edd82013-07-08 13:30:19 -0400983void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior)
984{
985 pp::SourceLocation srcLoc;
986 srcLoc.file = loc.first_file;
987 srcLoc.line = loc.first_line;
988 directiveHandler.handleExtension(srcLoc, extName, behavior);
989}
990
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700991void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -0400992{
993 pp::SourceLocation srcLoc;
994 srcLoc.file = loc.first_file;
995 srcLoc.line = loc.first_line;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700996 directiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -0400997}
998
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999/////////////////////////////////////////////////////////////////////////////////
1000//
1001// Non-Errors.
1002//
1003/////////////////////////////////////////////////////////////////////////////////
1004
Jamie Madill5c097022014-08-20 16:38:32 -04001005const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1006 const TString *name,
1007 const TSymbol *symbol)
1008{
1009 const TVariable *variable = NULL;
1010
1011 if (!symbol)
1012 {
1013 error(location, "undeclared identifier", name->c_str());
1014 recover();
1015 }
1016 else if (!symbol->isVariable())
1017 {
1018 error(location, "variable expected", name->c_str());
1019 recover();
1020 }
1021 else
1022 {
1023 variable = static_cast<const TVariable*>(symbol);
1024
1025 if (symbolTable.findBuiltIn(variable->getName(), shaderVersion) &&
1026 !variable->getExtension().empty() &&
1027 extensionErrorCheck(location, variable->getExtension()))
1028 {
1029 recover();
1030 }
1031 }
1032
1033 if (!variable)
1034 {
1035 TType type(EbtFloat, EbpUndefined);
1036 TVariable *fakeVariable = new TVariable(name, type);
1037 symbolTable.declare(fakeVariable);
1038 variable = fakeVariable;
1039 }
1040
1041 return variable;
1042}
1043
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044//
1045// Look up a function name in the symbol table, and make sure it is a function.
1046//
1047// Return the function symbol if found, otherwise 0.
1048//
Austin Kinross3ae64652015-01-26 15:51:39 -08001049const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int inputShaderVersion, bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001051 // First find by unmangled name to check whether the function name has been
1052 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001053 // If a function is found, check for one with a matching argument list.
Austin Kinross3ae64652015-01-26 15:51:39 -08001054 const TSymbol* symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001055 if (symbol == 0 || symbol->isFunction()) {
Austin Kinross3ae64652015-01-26 15:51:39 -08001056 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001057 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001058
alokp@chromium.org0a576182010-08-09 17:16:27 +00001059 if (symbol == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001060 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001061 return 0;
1062 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063
alokp@chromium.org0a576182010-08-09 17:16:27 +00001064 if (!symbol->isFunction()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001065 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001066 return 0;
1067 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001068
1069 return static_cast<const TFunction*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070}
1071
1072//
1073// Initializers show up in several places in the grammar. Have one set of
1074// code to handle them here.
1075//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001076// Returns true on error, false if no error
1077//
Olli Etuaho2935c582015-04-08 14:32:06 +03001078bool TParseContext::executeInitializer(const TSourceLoc &line, const TString &identifier, TPublicType &pType,
1079 TIntermTyped *initializer, TIntermNode *&intermNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001081 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082
Olli Etuaho2935c582015-04-08 14:32:06 +03001083 TVariable *variable = nullptr;
1084 if (!declareVariable(line, identifier, type, &variable))
1085 {
1086 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001087 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001089 //
1090 // identifier must be of type constant, a global, or a temporary
1091 //
1092 TQualifier qualifier = variable->getType().getQualifier();
1093 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001094 error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001095 return true;
1096 }
1097 //
1098 // test for and propagate constant
1099 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001100
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001101 if (qualifier == EvqConst) {
1102 if (qualifier != initializer->getType().getQualifier()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001103 std::stringstream extraInfoStream;
1104 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1105 std::string extraInfo = extraInfoStream.str();
1106 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001107 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001108 return true;
1109 }
1110 if (type != initializer->getType()) {
1111 error(line, " non-matching types for const initializer ",
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001112 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001113 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001114 return true;
1115 }
1116 if (initializer->getAsConstantUnion()) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001117 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001118 } else if (initializer->getAsSymbolNode()) {
shannonwoods@chromium.org96e7ba12013-05-30 00:02:41 +00001119 const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001120 const TVariable* tVar = static_cast<const TVariable*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001122 ConstantUnion* constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001123 variable->shareConstPointer(constArray);
1124 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001125 std::stringstream extraInfoStream;
1126 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1127 std::string extraInfo = extraInfoStream.str();
1128 error(line, " cannot assign to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001129 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001130 return true;
1131 }
1132 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001134 if (qualifier != EvqConst) {
1135 TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuahod6b14282015-03-17 14:31:35 +02001136 intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001137 if (intermNode == 0) {
1138 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1139 return true;
1140 }
1141 } else
1142 intermNode = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001144 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145}
1146
1147bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
1148{
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001149 ASSERT(aggrNode != NULL);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001150 if (!aggrNode->isConstructor())
1151 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001153 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001154
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001155 // check if all the child nodes are constants so that they can be inserted into
1156 // the parent node
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001157 TIntermSequence *sequence = aggrNode->getSequence() ;
1158 for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p) {
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001159 if (!(*p)->getAsTyped()->getAsConstantUnion())
1160 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001161 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001162
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001163 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001164}
1165
Jamie Madilla5efff92013-06-06 11:56:47 -04001166TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001167{
1168 TPublicType returnType = typeSpecifier;
1169 returnType.qualifier = qualifier;
Jamie Madilla5efff92013-06-06 11:56:47 -04001170 returnType.layoutQualifier = layoutQualifier;
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001171
1172 if (typeSpecifier.array)
1173 {
1174 error(typeSpecifier.line, "not supported", "first-class array");
1175 recover();
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001176 returnType.clearArrayness();
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001177 }
1178
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001179 if (shaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001180 {
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001181 if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1182 {
1183 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1184 recover();
1185 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001186
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001187 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1188 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1189 {
1190 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1191 recover();
1192 }
1193 }
1194 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001195 {
Jamie Madillb120eac2013-06-12 14:08:13 -04001196 switch (qualifier)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001197 {
Jamie Madill19571812013-08-12 15:26:34 -07001198 case EvqSmoothIn:
1199 case EvqSmoothOut:
1200 case EvqVertexOut:
1201 case EvqFragmentIn:
1202 case EvqCentroidOut:
1203 case EvqCentroidIn:
1204 if (typeSpecifier.type == EbtBool)
1205 {
1206 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1207 recover();
1208 }
1209 if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
1210 {
1211 error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
1212 recover();
1213 }
1214 break;
1215
1216 case EvqVertexIn:
1217 case EvqFragmentOut:
1218 case EvqFlatIn:
1219 case EvqFlatOut:
Jamie Madillb120eac2013-06-12 14:08:13 -04001220 if (typeSpecifier.type == EbtBool)
1221 {
1222 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1223 recover();
1224 }
1225 break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001226
Jamie Madillb120eac2013-06-12 14:08:13 -04001227 default: break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001228 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001229 }
1230
1231 return returnType;
1232}
1233
Olli Etuahofa33d582015-04-09 14:33:12 +03001234TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
1235 const TSourceLoc &identifierOrTypeLocation,
1236 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001237{
Olli Etuahofa33d582015-04-09 14:33:12 +03001238 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
1239 TIntermAggregate *aggregate = intermediate.makeAggregate(symbol, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001240
Olli Etuahofa33d582015-04-09 14:33:12 +03001241 mDeferredSingleDeclarationErrorCheck = (identifier == "");
1242
1243 if (!mDeferredSingleDeclarationErrorCheck)
Jamie Madill60ed9812013-06-06 11:56:46 -04001244 {
Olli Etuahofa33d582015-04-09 14:33:12 +03001245 if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001246 recover();
1247
Olli Etuahofa33d582015-04-09 14:33:12 +03001248 if (nonInitConstErrorCheck(identifierOrTypeLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001249 recover();
1250
Olli Etuaho2935c582015-04-08 14:32:06 +03001251 TVariable *variable = nullptr;
Olli Etuahofa33d582015-04-09 14:33:12 +03001252 if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001253 recover();
1254
1255 if (variable && symbol)
1256 {
1257 symbol->setId(variable->getUniqueId());
1258 }
1259 }
1260
1261 return aggregate;
1262}
1263
Jamie Madill075edd82013-07-08 13:30:19 -04001264TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001265{
Olli Etuahofa33d582015-04-09 14:33:12 +03001266 mDeferredSingleDeclarationErrorCheck = false;
1267
1268 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001269 recover();
1270
Olli Etuaho3739d232015-04-08 12:23:44 +03001271 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001272 recover();
1273
1274 if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
1275 {
1276 recover();
1277 }
1278
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001279 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001280
1281 int size;
1282 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1283 {
1284 recover();
1285 }
1286 else
1287 {
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001288 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001289 }
1290
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001291 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001292 TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001293
Olli Etuaho2935c582015-04-08 14:32:06 +03001294 TVariable *variable = nullptr;
1295 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001296 recover();
1297
1298 if (variable && symbol)
1299 {
1300 symbol->setId(variable->getUniqueId());
1301 }
1302
1303 return aggregate;
1304}
1305
Jamie Madill075edd82013-07-08 13:30:19 -04001306TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001307{
Olli Etuahofa33d582015-04-09 14:33:12 +03001308 mDeferredSingleDeclarationErrorCheck = false;
1309
1310 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001311 recover();
1312
1313 TIntermNode* intermNode;
1314 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1315 {
1316 //
1317 // Build intermediate representation
1318 //
1319 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL;
1320 }
1321 else
1322 {
1323 recover();
1324 return NULL;
1325 }
1326}
1327
Jamie Madill47e3ec02014-08-20 16:38:33 -04001328TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
1329 const TSourceLoc &identifierLoc,
1330 const TString *identifier,
1331 const TSymbol *symbol)
1332{
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001333 // invariant declaration
Jamie Madill47e3ec02014-08-20 16:38:33 -04001334 if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
1335 {
1336 recover();
1337 }
1338
1339 if (!symbol)
1340 {
1341 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
1342 recover();
Jamie Madill47e3ec02014-08-20 16:38:33 -04001343 return NULL;
1344 }
1345 else
1346 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001347 const TString kGlFrontFacing("gl_FrontFacing");
1348 if (*identifier == kGlFrontFacing)
1349 {
1350 error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str());
1351 recover();
1352 return NULL;
1353 }
Jamie Madill2c433252014-12-03 12:36:54 -05001354 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001355 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
1356 ASSERT(variable);
1357 const TType &type = variable->getType();
1358 TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(),
1359 *identifier, type, identifierLoc);
1360
1361 TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
1362 aggregate->setOp(EOpInvariantDeclaration);
1363 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001364 }
1365}
1366
Jamie Madill075edd82013-07-08 13:30:19 -04001367TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
Jamie Madill502d66f2013-06-20 11:55:52 -04001368{
Olli Etuahofa33d582015-04-09 14:33:12 +03001369 // If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
1370 if (mDeferredSingleDeclarationErrorCheck)
1371 {
1372 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1373 recover();
1374 mDeferredSingleDeclarationErrorCheck = false;
1375 }
1376
Jamie Madill502d66f2013-06-20 11:55:52 -04001377 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
1378 TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
1379
Jamie Madill0bd18df2013-06-20 11:55:52 -04001380 if (locationDeclaratorListCheck(identifierLocation, publicType))
1381 recover();
1382
Olli Etuaho3739d232015-04-08 12:23:44 +03001383 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001384 recover();
1385
Olli Etuaho2935c582015-04-08 14:32:06 +03001386 TVariable *variable = nullptr;
1387 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001388 recover();
1389 if (symbol && variable)
1390 symbol->setId(variable->getUniqueId());
1391
1392 return intermAggregate;
1393}
1394
Jamie Madill075edd82013-07-08 13:30:19 -04001395TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression)
Jamie Madill502d66f2013-06-20 11:55:52 -04001396{
Olli Etuahofa33d582015-04-09 14:33:12 +03001397 // If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
1398 if (mDeferredSingleDeclarationErrorCheck)
1399 {
1400 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1401 recover();
1402 mDeferredSingleDeclarationErrorCheck = false;
1403 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001404
Jamie Madill0bd18df2013-06-20 11:55:52 -04001405 if (locationDeclaratorListCheck(identifierLocation, publicType))
1406 recover();
1407
Olli Etuaho3739d232015-04-08 12:23:44 +03001408 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001409 recover();
1410
1411 if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
1412 {
1413 recover();
1414 }
Olli Etuaho93a90fd2015-04-07 18:14:07 +03001415 else
Jamie Madill502d66f2013-06-20 11:55:52 -04001416 {
1417 int size;
1418 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
1419 recover();
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001420 TType arrayType = TType(publicType);
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001421 arrayType.setArraySize(size);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001422 TVariable *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +03001423 if (!declareVariable(arrayLocation, identifier, arrayType, &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001424 recover();
Jamie Madill502d66f2013-06-20 11:55:52 -04001425
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001426 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
1427 if (variable && symbol)
1428 {
1429 symbol->setId(variable->getUniqueId());
1430 }
1431 return intermediate.growAggregate(declaratorList, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001432 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001433
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001434 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001435}
1436
Jamie Madill075edd82013-07-08 13:30:19 -04001437TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
Jamie Madill502d66f2013-06-20 11:55:52 -04001438{
Olli Etuahofa33d582015-04-09 14:33:12 +03001439 // If the declaration starting this declarator list was empty (example: int,), some checks were not performed.
1440 if (mDeferredSingleDeclarationErrorCheck)
1441 {
1442 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1443 recover();
1444 mDeferredSingleDeclarationErrorCheck = false;
1445 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001446
Jamie Madill0bd18df2013-06-20 11:55:52 -04001447 if (locationDeclaratorListCheck(identifierLocation, publicType))
1448 recover();
1449
Jamie Madill502d66f2013-06-20 11:55:52 -04001450 TIntermNode* intermNode;
1451 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1452 {
1453 //
1454 // build the intermediate representation
1455 //
1456 if (intermNode)
1457 {
1458 return intermediate.growAggregate(declaratorList, intermNode, initLocation);
1459 }
1460 else
1461 {
1462 return declaratorList;
1463 }
1464 }
1465 else
1466 {
1467 recover();
1468 return NULL;
1469 }
1470}
1471
Jamie Madilla295edf2013-06-06 11:56:48 -04001472void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1473{
1474 if (typeQualifier.qualifier != EvqUniform)
1475 {
1476 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
1477 recover();
1478 return;
1479 }
1480
1481 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1482 ASSERT(!layoutQualifier.isEmpty());
1483
1484 if (shaderVersion < 300)
1485 {
1486 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1487 recover();
1488 return;
1489 }
1490
1491 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1492 {
1493 recover();
1494 return;
1495 }
1496
Jamie Madill099c0f32013-06-20 11:55:52 -04001497 if (layoutQualifier.matrixPacking != EmpUnspecified)
1498 {
1499 defaultMatrixPacking = layoutQualifier.matrixPacking;
1500 }
1501
Geoff Langc6856732014-02-11 09:38:55 -05001502 if (layoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001503 {
1504 defaultBlockStorage = layoutQualifier.blockStorage;
1505 }
Jamie Madilla295edf2013-06-06 11:56:48 -04001506}
1507
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001508TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
1509{
1510 TOperator op = EOpNull;
1511 if (publicType.userDef)
1512 {
1513 op = EOpConstructStruct;
1514 }
1515 else
1516 {
1517 switch (publicType.type)
1518 {
1519 case EbtFloat:
1520 if (publicType.isMatrix())
1521 {
1522 // TODO: non-square matrices
1523 switch(publicType.getCols())
1524 {
Jamie Madill28b97422013-07-08 14:01:38 -04001525 case 2: op = EOpConstructMat2; break;
1526 case 3: op = EOpConstructMat3; break;
1527 case 4: op = EOpConstructMat4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001528 }
1529 }
1530 else
1531 {
1532 switch(publicType.getNominalSize())
1533 {
Jamie Madill28b97422013-07-08 14:01:38 -04001534 case 1: op = EOpConstructFloat; break;
1535 case 2: op = EOpConstructVec2; break;
1536 case 3: op = EOpConstructVec3; break;
1537 case 4: op = EOpConstructVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001538 }
1539 }
1540 break;
1541
1542 case EbtInt:
1543 switch(publicType.getNominalSize())
1544 {
Jamie Madill28b97422013-07-08 14:01:38 -04001545 case 1: op = EOpConstructInt; break;
1546 case 2: op = EOpConstructIVec2; break;
1547 case 3: op = EOpConstructIVec3; break;
1548 case 4: op = EOpConstructIVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001549 }
1550 break;
1551
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001552 case EbtUInt:
1553 switch(publicType.getNominalSize())
1554 {
Jamie Madill28b97422013-07-08 14:01:38 -04001555 case 1: op = EOpConstructUInt; break;
1556 case 2: op = EOpConstructUVec2; break;
1557 case 3: op = EOpConstructUVec3; break;
1558 case 4: op = EOpConstructUVec4; break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001559 }
1560 break;
1561
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001562 case EbtBool:
1563 switch(publicType.getNominalSize())
1564 {
Jamie Madill28b97422013-07-08 14:01:38 -04001565 case 1: op = EOpConstructBool; break;
1566 case 2: op = EOpConstructBVec2; break;
1567 case 3: op = EOpConstructBVec3; break;
1568 case 4: op = EOpConstructBVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001569 }
1570 break;
1571
1572 default: break;
1573 }
1574
1575 if (op == EOpNull)
1576 {
1577 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
1578 recover();
1579 publicType.type = EbtFloat;
1580 op = EOpConstructFloat;
1581 }
1582 }
1583
1584 TString tempString;
1585 TType type(publicType);
1586 return new TFunction(&tempString, type, op);
1587}
1588
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001589// This function is used to test for the correctness of the parameters passed to various constructor functions
1590// and also convert them to the right datatype if it is allowed and required.
1591//
1592// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
1593//
Olli Etuaho21203702014-11-13 16:16:21 +02001594TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001595{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001596 TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001597
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001598 if (!aggregateArguments)
1599 {
1600 aggregateArguments = new TIntermAggregate;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001601 aggregateArguments->getSequence()->push_back(arguments);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001602 }
1603
Olli Etuahof40319e2015-03-10 14:33:00 +02001604 if (type->isArray())
1605 {
1606 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of the array.
1607 TIntermSequence *args = aggregateArguments->getSequence();
1608 for (size_t i = 0; i < args->size(); i++)
1609 {
1610 const TType &argType = (*args)[i]->getAsTyped()->getType();
1611 // It has already been checked that the argument is not an array.
1612 ASSERT(!argType.isArray());
1613 if (!argType.sameElementType(*type))
1614 {
1615 error(line, "Array constructor argument has an incorrect type", "Error");
1616 recover();
1617 return nullptr;
1618 }
1619 }
1620 }
1621 else if (op == EOpConstructStruct)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001622 {
1623 const TFieldList &fields = type->getStruct()->fields();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001624 TIntermSequence *args = aggregateArguments->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001625
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001626 for (size_t i = 0; i < fields.size(); i++)
1627 {
Nicolas Capensffd73872014-08-21 13:49:16 -04001628 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001629 {
1630 error(line, "Structure constructor arguments do not match structure fields", "Error");
1631 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001632
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001633 return 0;
1634 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001635 }
1636 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001638 // Turn the argument list itself into a constructor
Olli Etuaho21203702014-11-13 16:16:21 +02001639 TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
1640 TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001641 if (constConstructor)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001642 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001643 return constConstructor;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001644 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645
Olli Etuaho21203702014-11-13 16:16:21 +02001646 // Structs should not be precision qualified, the individual members may be.
1647 // Built-in types on the other hand should be precision qualified.
1648 if (op != EOpConstructStruct)
1649 {
1650 constructor->setPrecisionFromChildren();
1651 type->setPrecision(constructor->getPrecision());
1652 }
1653
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001654 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655}
1656
1657TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
1658{
Olli Etuahof40319e2015-03-10 14:33:00 +02001659 // TODO: Add support for folding array constructors
1660 bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001661 aggrNode->setType(type);
1662 if (canBeFolded) {
1663 bool returnVal = false;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001664 ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001665 if (aggrNode->getSequence()->size() == 1) {
shannonwoods@chromium.org298f9072013-05-30 00:21:17 +00001666 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001667 }
1668 else {
shannonwoods@chromium.org298f9072013-05-30 00:21:17 +00001669 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001670 }
1671 if (returnVal)
1672 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001674 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
1675 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001676
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001677 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001678}
1679
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001680//
1681// This function returns the tree representation for the vector field(s) being accessed from contant vector.
1682// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
1683// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
1684// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
1685// a constant matrix.
1686//
Jamie Madill075edd82013-07-08 13:30:19 -04001687TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001688{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001689 TIntermTyped* typedNode;
1690 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001691
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001692 ConstantUnion *unionArray;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001693 if (tempConstantNode) {
1694 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001695
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001696 if (!unionArray) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001697 return node;
1698 }
1699 } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001700 error(line, "Cannot offset into the vector", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001701 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001702
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001703 return 0;
1704 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001705
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001706 ConstantUnion* constArray = new ConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001708 for (int i = 0; i < fields.num; i++) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001709 if (fields.offsets[i] >= node->getType().getNominalSize()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001710 std::stringstream extraInfoStream;
1711 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
1712 std::string extraInfo = extraInfoStream.str();
1713 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001714 recover();
1715 fields.offsets[i] = 0;
1716 }
1717
1718 constArray[i] = unionArray[fields.offsets[i]];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001719
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001720 }
1721 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
1722 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001723}
1724
1725//
1726// This function returns the column being accessed from a constant matrix. The values are retrieved from
1727// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
1728// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
1729// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
1730//
Jamie Madill075edd82013-07-08 13:30:19 -04001731TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001732{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001733 TIntermTyped* typedNode;
1734 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001735
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001736 if (index >= node->getType().getCols()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001737 std::stringstream extraInfoStream;
1738 extraInfoStream << "matrix field selection out of range '" << index << "'";
1739 std::string extraInfo = extraInfoStream.str();
1740 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001741 recover();
1742 index = 0;
1743 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001744
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001745 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001746 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00001747 int size = tempConstantNode->getType().getCols();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001748 typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
1749 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001750 error(line, "Cannot offset into the matrix", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001751 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001753 return 0;
1754 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001755
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001756 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001757}
1758
1759
1760//
1761// This function returns an element of an array accessed from a constant array. The values are retrieved from
1762// the symbol table and parse-tree is built for the type of the element. The input
1763// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
1764// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
1765//
Jamie Madill075edd82013-07-08 13:30:19 -04001766TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001768 TIntermTyped* typedNode;
1769 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1770 TType arrayElementType = node->getType();
1771 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001772
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001773 if (index >= node->getType().getArraySize()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001774 std::stringstream extraInfoStream;
1775 extraInfoStream << "array field selection out of range '" << index << "'";
1776 std::string extraInfo = extraInfoStream.str();
1777 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001778 recover();
1779 index = 0;
1780 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001781
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001782 if (tempConstantNode) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001783 size_t arrayElementSize = arrayElementType.getObjectSize();
1784 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
1785 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001786 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001787 error(line, "Cannot offset into the array", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001788 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001790 return 0;
1791 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001792
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001793 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001794}
1795
1796
1797//
1798// This function returns the value of a particular field inside a constant structure from the symbol table.
1799// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
1800// function and returns the parse-tree with the values of the embedded/nested struct.
1801//
Jamie Madill075edd82013-07-08 13:30:19 -04001802TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001803{
Jamie Madill98493dd2013-07-08 14:39:03 -04001804 const TFieldList& fields = node->getType().getStruct()->fields();
Jamie Madill94bf7f22013-07-08 13:31:15 -04001805 size_t instanceSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001806
Jamie Madill98493dd2013-07-08 14:39:03 -04001807 for (size_t index = 0; index < fields.size(); ++index) {
1808 if (fields[index]->name() == identifier) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001809 break;
1810 } else {
Jamie Madill98493dd2013-07-08 14:39:03 -04001811 instanceSize += fields[index]->type()->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001812 }
1813 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814
Jamie Madill94bf7f22013-07-08 13:31:15 -04001815 TIntermTyped *typedNode;
1816 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001817 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001818 ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001819
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001820 typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
1821 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001822 error(line, "Cannot offset into the structure", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001823 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001824
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001825 return 0;
1826 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001827
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001828 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001829}
1830
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001831//
1832// Interface/uniform blocks
1833//
Jamie Madill98493dd2013-07-08 14:39:03 -04001834TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
1835 const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001836{
1837 if (reservedErrorCheck(nameLine, blockName))
1838 recover();
1839
1840 if (typeQualifier.qualifier != EvqUniform)
1841 {
1842 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
1843 recover();
1844 }
1845
Jamie Madill099c0f32013-06-20 11:55:52 -04001846 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
1847 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001848 {
1849 recover();
1850 }
1851
Jamie Madill099c0f32013-06-20 11:55:52 -04001852 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
1853 {
1854 blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
1855 }
1856
Jamie Madill1566ef72013-06-20 11:55:54 -04001857 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
1858 {
1859 blockLayoutQualifier.blockStorage = defaultBlockStorage;
1860 }
1861
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001862 TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
Nicolas Capensadfffe42014-06-17 02:13:36 -04001863 if (!symbolTable.declare(blockNameSymbol)) {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001864 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
1865 recover();
1866 }
1867
Jamie Madill98493dd2013-07-08 14:39:03 -04001868 // check for sampler types and apply layout qualifiers
1869 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
1870 TField* field = (*fieldList)[memberIndex];
1871 TType* fieldType = field->type();
1872 if (IsSampler(fieldType->getBasicType())) {
1873 error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001874 recover();
1875 }
1876
Jamie Madill98493dd2013-07-08 14:39:03 -04001877 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001878 switch (qualifier)
1879 {
1880 case EvqGlobal:
1881 case EvqUniform:
1882 break;
1883 default:
Jamie Madill98493dd2013-07-08 14:39:03 -04001884 error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001885 recover();
1886 break;
1887 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001888
1889 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04001890 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
1891 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001892 {
1893 recover();
1894 }
Jamie Madill099c0f32013-06-20 11:55:52 -04001895
Jamie Madill98493dd2013-07-08 14:39:03 -04001896 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001897 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001898 error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04001899 recover();
1900 }
1901
Jamie Madill98493dd2013-07-08 14:39:03 -04001902 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04001903 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001904 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04001905 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001906 else if (!fieldType->isMatrix())
Jamie Madill099c0f32013-06-20 11:55:52 -04001907 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001908 error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04001909 recover();
1910 }
1911
Jamie Madill98493dd2013-07-08 14:39:03 -04001912 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001913 }
1914
Jamie Madill98493dd2013-07-08 14:39:03 -04001915 // add array index
1916 int arraySize = 0;
1917 if (arrayIndex != NULL)
1918 {
1919 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
1920 recover();
1921 }
1922
1923 TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
1924 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001925
1926 TString symbolName = "";
1927 int symbolId = 0;
1928
Jamie Madill98493dd2013-07-08 14:39:03 -04001929 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001930 {
1931 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04001932 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
1933 {
1934 TField* field = (*fieldList)[memberIndex];
1935 TType* fieldType = field->type();
1936
1937 // set parent pointer of the field variable
1938 fieldType->setInterfaceBlock(interfaceBlock);
1939
1940 TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
1941 fieldVariable->setQualifier(typeQualifier.qualifier);
1942
Nicolas Capensadfffe42014-06-17 02:13:36 -04001943 if (!symbolTable.declare(fieldVariable)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04001944 error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001945 recover();
1946 }
1947 }
1948 }
1949 else
1950 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001951 // add a symbol for this interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04001952 TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001953 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04001954
Nicolas Capensadfffe42014-06-17 02:13:36 -04001955 if (!symbolTable.declare(instanceTypeDef)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04001956 error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001957 recover();
1958 }
1959
1960 symbolId = instanceTypeDef->getUniqueId();
1961 symbolName = instanceTypeDef->getName();
1962 }
1963
Jamie Madill98493dd2013-07-08 14:39:03 -04001964 TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001965 aggregate->setOp(EOpDeclaration);
Jamie Madill98493dd2013-07-08 14:39:03 -04001966
1967 exitStructDeclaration();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001968 return aggregate;
1969}
1970
Jamie Madill075edd82013-07-08 13:30:19 -04001971bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00001972{
1973 ++structNestingLevel;
1974
1975 // Embedded structure definitions are not supported per GLSL ES spec.
1976 // They aren't allowed in GLSL either, but we need to detect this here
1977 // so we don't rely on the GLSL compiler to catch it.
1978 if (structNestingLevel > 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001979 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00001980 return true;
1981 }
1982
1983 return false;
1984}
1985
1986void TParseContext::exitStructDeclaration()
1987{
1988 --structNestingLevel;
1989}
1990
1991namespace {
1992
1993const int kWebGLMaxStructNesting = 4;
1994
1995} // namespace
1996
Jamie Madill98493dd2013-07-08 14:39:03 -04001997bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00001998{
Jamie Madill5508f392014-02-20 13:31:36 -05001999 if (!IsWebGLBasedSpec(shaderSpec)) {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002000 return false;
2001 }
2002
Jamie Madill98493dd2013-07-08 14:39:03 -04002003 if (field.type()->getBasicType() != EbtStruct) {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002004 return false;
2005 }
2006
2007 // We're already inside a structure definition at this point, so add
2008 // one to the field's struct nesting.
Jamie Madill98493dd2013-07-08 14:39:03 -04002009 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
Jamie Madill41a49272014-03-18 16:10:13 -04002010 std::stringstream reasonStream;
2011 reasonStream << "Reference of struct type "
2012 << field.type()->getStruct()->name().c_str()
2013 << " exceeds maximum allowed nesting level of "
2014 << kWebGLMaxStructNesting;
2015 std::string reason = reasonStream.str();
2016 error(line, reason.c_str(), field.name().c_str(), "");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002017 return true;
2018 }
2019
2020 return false;
2021}
2022
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00002023//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002024// Parse an array index expression
2025//
Jamie Madill075edd82013-07-08 13:30:19 -04002026TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002027{
2028 TIntermTyped *indexedExpression = NULL;
2029
2030 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2031 {
2032 if (baseExpression->getAsSymbolNode())
2033 {
2034 error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
2035 }
2036 else
2037 {
2038 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2039 }
2040 recover();
2041 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002042
Jamie Madill21c1e452014-12-29 11:33:41 -05002043 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2044
2045 if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04002046 {
Jamie Madill21c1e452014-12-29 11:33:41 -05002047 int index = indexConstantUnion->getIConst(0);
Jamie Madill7164cf42013-07-08 13:30:59 -04002048 if (index < 0)
2049 {
2050 std::stringstream infoStream;
2051 infoStream << index;
2052 std::string info = infoStream.str();
2053 error(location, "negative index", info.c_str());
2054 recover();
2055 index = 0;
2056 }
2057 if (baseExpression->getType().getQualifier() == EvqConst)
2058 {
2059 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002060 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002061 // constant folding for arrays
2062 indexedExpression = addConstArrayNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002063 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002064 else if (baseExpression->isVector())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002065 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002066 // constant folding for vectors
2067 TVectorFields fields;
2068 fields.num = 1;
2069 fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
2070 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2071 }
2072 else if (baseExpression->isMatrix())
2073 {
2074 // constant folding for matrices
2075 indexedExpression = addConstMatrixNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002076 }
2077 }
2078 else
2079 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002080 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002081 {
Jamie Madill18464b52013-07-08 14:01:55 -04002082 if (index >= baseExpression->getType().getArraySize())
Jamie Madill7164cf42013-07-08 13:30:59 -04002083 {
2084 std::stringstream extraInfoStream;
2085 extraInfoStream << "array index out of range '" << index << "'";
2086 std::string extraInfo = extraInfoStream.str();
2087 error(location, "", "[", extraInfo.c_str());
2088 recover();
2089 index = baseExpression->getType().getArraySize() - 1;
2090 }
Jamie Madill5d287f52013-07-12 15:38:19 -04002091 else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
2092 {
2093 error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
2094 recover();
2095 index = 0;
2096 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002097 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002098 else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002099 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002100 std::stringstream extraInfoStream;
2101 extraInfoStream << "field selection out of range '" << index << "'";
2102 std::string extraInfo = extraInfoStream.str();
2103 error(location, "", "[", extraInfo.c_str());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002104 recover();
Jamie Madill7164cf42013-07-08 13:30:59 -04002105 index = baseExpression->getType().getNominalSize() - 1;
Jamie Madill46131a32013-06-20 11:55:50 -04002106 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002107
Jamie Madill21c1e452014-12-29 11:33:41 -05002108 indexConstantUnion->getUnionArrayPointer()->setIConst(index);
Jamie Madill7164cf42013-07-08 13:30:59 -04002109 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002110 }
2111 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002112 else
2113 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002114 if (baseExpression->isInterfaceBlock())
Jamie Madill7164cf42013-07-08 13:30:59 -04002115 {
Jamie Madill19571812013-08-12 15:26:34 -07002116 error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002117 recover();
2118 }
Jamie Madill19571812013-08-12 15:26:34 -07002119 else if (baseExpression->getQualifier() == EvqFragmentOut)
Jamie Madill7164cf42013-07-08 13:30:59 -04002120 {
Jamie Madill19571812013-08-12 15:26:34 -07002121 error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002122 recover();
2123 }
2124
2125 indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
2126 }
2127
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002128 if (indexedExpression == 0)
2129 {
2130 ConstantUnion *unionArray = new ConstantUnion[1];
2131 unionArray->setFConst(0.0f);
2132 indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
2133 }
2134 else if (baseExpression->isArray())
2135 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002136 const TType &baseType = baseExpression->getType();
2137 if (baseType.getStruct())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002138 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002139 TType copyOfType(baseType.getStruct());
2140 indexedExpression->setType(copyOfType);
2141 }
2142 else if (baseType.isInterfaceBlock())
2143 {
2144 TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002145 indexedExpression->setType(copyOfType);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002146 }
2147 else
2148 {
Minmin Gong794e0002015-04-07 18:31:54 -07002149 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary,
2150 static_cast<unsigned char>(baseExpression->getNominalSize()), static_cast<unsigned char>(baseExpression->getSecondarySize())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002151 }
2152
2153 if (baseExpression->getType().getQualifier() == EvqConst)
2154 {
2155 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2156 }
2157 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002158 else if (baseExpression->isMatrix())
2159 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002160 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
Minmin Gong794e0002015-04-07 18:31:54 -07002161 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002162 }
2163 else if (baseExpression->isVector())
2164 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002165 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2166 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002167 }
2168 else
2169 {
2170 indexedExpression->setType(baseExpression->getType());
2171 }
2172
2173 return indexedExpression;
2174}
2175
Jamie Madill075edd82013-07-08 13:30:19 -04002176TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002177{
2178 TIntermTyped *indexedExpression = NULL;
2179
2180 if (baseExpression->isArray())
2181 {
2182 error(fieldLocation, "cannot apply dot operator to an array", ".");
2183 recover();
2184 }
2185
2186 if (baseExpression->isVector())
2187 {
2188 TVectorFields fields;
2189 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation))
2190 {
2191 fields.num = 1;
2192 fields.offsets[0] = 0;
2193 recover();
2194 }
2195
2196 if (baseExpression->getType().getQualifier() == EvqConst)
2197 {
2198 // constant folding for vector fields
2199 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2200 if (indexedExpression == 0)
2201 {
2202 recover();
2203 indexedExpression = baseExpression;
2204 }
2205 else
2206 {
Minmin Gong794e0002015-04-07 18:31:54 -07002207 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (unsigned char) (fieldString).size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002208 }
2209 }
2210 else
2211 {
2212 TString vectorString = fieldString;
2213 TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation);
2214 indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
Minmin Gong794e0002015-04-07 18:31:54 -07002215 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (unsigned char) vectorString.size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002216 }
2217 }
2218 else if (baseExpression->isMatrix())
2219 {
2220 TMatrixFields fields;
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002221 if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002222 {
2223 fields.wholeRow = false;
2224 fields.wholeCol = false;
2225 fields.row = 0;
2226 fields.col = 0;
2227 recover();
2228 }
2229
2230 if (fields.wholeRow || fields.wholeCol)
2231 {
2232 error(dotLocation, " non-scalar fields not implemented yet", ".");
2233 recover();
2234 ConstantUnion *unionArray = new ConstantUnion[1];
2235 unionArray->setIConst(0);
2236 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2237 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
Minmin Gong794e0002015-04-07 18:31:54 -07002238 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary,
2239 static_cast<unsigned char>(baseExpression->getCols()), static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002240 }
2241 else
2242 {
2243 ConstantUnion *unionArray = new ConstantUnion[1];
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002244 unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002245 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2246 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
2247 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
2248 }
2249 }
2250 else if (baseExpression->getBasicType() == EbtStruct)
2251 {
2252 bool fieldFound = false;
Jamie Madill98493dd2013-07-08 14:39:03 -04002253 const TFieldList& fields = baseExpression->getType().getStruct()->fields();
2254 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002255 {
2256 error(dotLocation, "structure has no fields", "Internal Error");
2257 recover();
2258 indexedExpression = baseExpression;
2259 }
2260 else
2261 {
2262 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002263 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002264 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002265 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002266 {
2267 fieldFound = true;
2268 break;
2269 }
2270 }
2271 if (fieldFound)
2272 {
2273 if (baseExpression->getType().getQualifier() == EvqConst)
2274 {
2275 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
2276 if (indexedExpression == 0)
2277 {
2278 recover();
2279 indexedExpression = baseExpression;
2280 }
2281 else
2282 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002283 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002284 // change the qualifier of the return type, not of the structure field
2285 // as the structure definition is shared between various structures.
2286 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2287 }
2288 }
2289 else
2290 {
2291 ConstantUnion *unionArray = new ConstantUnion[1];
2292 unionArray->setIConst(i);
Jamie Madill98493dd2013-07-08 14:39:03 -04002293 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002294 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04002295 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002296 }
2297 }
2298 else
2299 {
2300 error(dotLocation, " no such field in structure", fieldString.c_str());
2301 recover();
2302 indexedExpression = baseExpression;
2303 }
2304 }
2305 }
Jamie Madill98493dd2013-07-08 14:39:03 -04002306 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002307 {
2308 bool fieldFound = false;
Jamie Madill98493dd2013-07-08 14:39:03 -04002309 const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields();
2310 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002311 {
2312 error(dotLocation, "interface block has no fields", "Internal Error");
2313 recover();
2314 indexedExpression = baseExpression;
2315 }
2316 else
2317 {
2318 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002319 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002320 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002321 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002322 {
2323 fieldFound = true;
2324 break;
2325 }
2326 }
2327 if (fieldFound)
2328 {
2329 ConstantUnion *unionArray = new ConstantUnion[1];
2330 unionArray->setIConst(i);
Jamie Madill98493dd2013-07-08 14:39:03 -04002331 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002332 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04002333 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002334 }
2335 else
2336 {
2337 error(dotLocation, " no such field in interface block", fieldString.c_str());
2338 recover();
2339 indexedExpression = baseExpression;
2340 }
2341 }
2342 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002343 else
2344 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002345 if (shaderVersion < 300)
2346 {
2347 error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
2348 }
2349 else
2350 {
2351 error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
2352 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002353 recover();
2354 indexedExpression = baseExpression;
2355 }
2356
2357 return indexedExpression;
2358}
2359
Jamie Madill075edd82013-07-08 13:30:19 -04002360TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002361{
Jamie Madilla5efff92013-06-06 11:56:47 -04002362 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002363
Jamie Madilla5efff92013-06-06 11:56:47 -04002364 qualifier.location = -1;
2365 qualifier.matrixPacking = EmpUnspecified;
2366 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002367
2368 if (qualifierType == "shared")
2369 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002370 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002371 }
2372 else if (qualifierType == "packed")
2373 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002374 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002375 }
2376 else if (qualifierType == "std140")
2377 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002378 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002379 }
2380 else if (qualifierType == "row_major")
2381 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002382 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002383 }
2384 else if (qualifierType == "column_major")
2385 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002386 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002387 }
2388 else if (qualifierType == "location")
2389 {
2390 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument");
2391 recover();
2392 }
2393 else
2394 {
2395 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
2396 recover();
2397 }
2398
Jamie Madilla5efff92013-06-06 11:56:47 -04002399 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002400}
2401
Jamie Madill075edd82013-07-08 13:30:19 -04002402TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002403{
Jamie Madilla5efff92013-06-06 11:56:47 -04002404 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002405
Jamie Madilla5efff92013-06-06 11:56:47 -04002406 qualifier.location = -1;
2407 qualifier.matrixPacking = EmpUnspecified;
2408 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002409
2410 if (qualifierType != "location")
2411 {
2412 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments");
2413 recover();
2414 }
2415 else
2416 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04002417 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002418 if (intValue < 0)
2419 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04002420 error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002421 recover();
2422 }
2423 else
2424 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002425 qualifier.location = intValue;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002426 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002427 }
2428
Jamie Madilla5efff92013-06-06 11:56:47 -04002429 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002430}
2431
Jamie Madilla5efff92013-06-06 11:56:47 -04002432TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002433{
Jamie Madilla5efff92013-06-06 11:56:47 -04002434 TLayoutQualifier joinedQualifier = leftQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002435
Jamie Madilla5efff92013-06-06 11:56:47 -04002436 if (rightQualifier.location != -1)
2437 {
2438 joinedQualifier.location = rightQualifier.location;
2439 }
2440 if (rightQualifier.matrixPacking != EmpUnspecified)
2441 {
2442 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
2443 }
2444 if (rightQualifier.blockStorage != EbsUnspecified)
2445 {
2446 joinedQualifier.blockStorage = rightQualifier.blockStorage;
2447 }
2448
2449 return joinedQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002450}
2451
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002452TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
2453 const TSourceLoc &storageLoc, TQualifier storageQualifier)
2454{
2455 TQualifier mergedQualifier = EvqSmoothIn;
2456
Jamie Madill19571812013-08-12 15:26:34 -07002457 if (storageQualifier == EvqFragmentIn) {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002458 if (interpolationQualifier == EvqSmooth)
2459 mergedQualifier = EvqSmoothIn;
2460 else if (interpolationQualifier == EvqFlat)
2461 mergedQualifier = EvqFlatIn;
2462 else UNREACHABLE();
2463 }
2464 else if (storageQualifier == EvqCentroidIn) {
2465 if (interpolationQualifier == EvqSmooth)
2466 mergedQualifier = EvqCentroidIn;
2467 else if (interpolationQualifier == EvqFlat)
2468 mergedQualifier = EvqFlatIn;
2469 else UNREACHABLE();
2470 }
Jamie Madill19571812013-08-12 15:26:34 -07002471 else if (storageQualifier == EvqVertexOut) {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002472 if (interpolationQualifier == EvqSmooth)
2473 mergedQualifier = EvqSmoothOut;
2474 else if (interpolationQualifier == EvqFlat)
2475 mergedQualifier = EvqFlatOut;
2476 else UNREACHABLE();
2477 }
2478 else if (storageQualifier == EvqCentroidOut) {
2479 if (interpolationQualifier == EvqSmooth)
2480 mergedQualifier = EvqCentroidOut;
2481 else if (interpolationQualifier == EvqFlat)
2482 mergedQualifier = EvqFlatOut;
2483 else UNREACHABLE();
2484 }
2485 else {
2486 error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier));
2487 recover();
2488
2489 mergedQualifier = storageQualifier;
2490 }
2491
2492 TPublicType type;
2493 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
2494 return type;
2495}
2496
Jamie Madill98493dd2013-07-08 14:39:03 -04002497TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002498{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002499 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
2500 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002501 recover();
2502 }
2503
Jamie Madill98493dd2013-07-08 14:39:03 -04002504 for (unsigned int i = 0; i < fieldList->size(); ++i) {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002505 //
2506 // Careful not to replace already known aspects of type, like array-ness
2507 //
Jamie Madill98493dd2013-07-08 14:39:03 -04002508 TType* type = (*fieldList)[i]->type();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002509 type->setBasicType(typeSpecifier.type);
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002510 type->setPrimarySize(typeSpecifier.primarySize);
2511 type->setSecondarySize(typeSpecifier.secondarySize);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002512 type->setPrecision(typeSpecifier.precision);
2513 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04002514 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002515
2516 // don't allow arrays of arrays
2517 if (type->isArray()) {
2518 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
2519 recover();
2520 }
2521 if (typeSpecifier.array)
2522 type->setArraySize(typeSpecifier.arraySize);
2523 if (typeSpecifier.userDef) {
2524 type->setStruct(typeSpecifier.userDef->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002525 }
2526
Jamie Madill98493dd2013-07-08 14:39:03 -04002527 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002528 recover();
2529 }
2530 }
2531
Jamie Madill98493dd2013-07-08 14:39:03 -04002532 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002533}
2534
Jamie Madill98493dd2013-07-08 14:39:03 -04002535TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002536{
Jamie Madill98493dd2013-07-08 14:39:03 -04002537 TStructure* structure = new TStructure(structName, fieldList);
2538 TType* structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002539
Jamie Madill9b820842015-02-12 10:40:10 -05002540 // Store a bool in the struct if we're at global scope, to allow us to
2541 // skip the local struct scoping workaround in HLSL.
Jamie Madillb960cc42015-02-12 15:33:20 +00002542 structure->setUniqueId(TSymbolTable::nextUniqueId());
Jamie Madill9b820842015-02-12 10:40:10 -05002543 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04002544
Jamie Madill98493dd2013-07-08 14:39:03 -04002545 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002546 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002547 if (reservedErrorCheck(nameLine, *structName))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002548 {
2549 recover();
2550 }
Jamie Madill98493dd2013-07-08 14:39:03 -04002551 TVariable* userTypeDef = new TVariable(structName, *structureType, true);
Nicolas Capensadfffe42014-06-17 02:13:36 -04002552 if (!symbolTable.declare(userTypeDef)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04002553 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002554 recover();
2555 }
2556 }
2557
2558 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04002559 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002560 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002561 const TField &field = *(*fieldList)[typeListIndex];
2562 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002563 switch (qualifier)
2564 {
2565 case EvqGlobal:
2566 case EvqTemporary:
2567 break;
2568 default:
Jamie Madill98493dd2013-07-08 14:39:03 -04002569 error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002570 recover();
2571 break;
2572 }
2573 }
2574
2575 TPublicType publicType;
2576 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04002577 publicType.userDef = structureType;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002578 exitStructDeclaration();
2579
2580 return publicType;
2581}
2582
Olli Etuahoa3a36662015-02-17 13:46:51 +02002583TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
2584{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002585 TBasicType switchType = init->getBasicType();
2586 if ((switchType != EbtInt && switchType != EbtUInt) ||
2587 init->isMatrix() ||
2588 init->isArray() ||
2589 init->isVector())
2590 {
2591 error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
2592 recover();
2593 return nullptr;
2594 }
2595
Olli Etuahoac5274d2015-02-20 10:19:08 +02002596 if (statementList)
2597 {
2598 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
2599 {
2600 recover();
2601 return nullptr;
2602 }
2603 }
2604
Olli Etuahoa3a36662015-02-17 13:46:51 +02002605 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
2606 if (node == nullptr)
2607 {
2608 error(loc, "erroneous switch statement", "switch");
2609 recover();
2610 return nullptr;
2611 }
2612 return node;
2613}
2614
2615TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
2616{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002617 if (mSwitchNestingLevel == 0)
2618 {
2619 error(loc, "case labels need to be inside switch statements", "case");
2620 recover();
2621 return nullptr;
2622 }
2623 if (condition == nullptr)
2624 {
2625 error(loc, "case label must have a condition", "case");
2626 recover();
2627 return nullptr;
2628 }
2629 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
2630 condition->isMatrix() ||
2631 condition->isArray() ||
2632 condition->isVector())
2633 {
2634 error(condition->getLine(), "case label must be a scalar integer", "case");
2635 recover();
2636 }
2637 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
2638 if (conditionConst == nullptr)
2639 {
2640 error(condition->getLine(), "case label must be constant", "case");
2641 recover();
2642 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02002643 TIntermCase *node = intermediate.addCase(condition, loc);
2644 if (node == nullptr)
2645 {
2646 error(loc, "erroneous case statement", "case");
2647 recover();
2648 return nullptr;
2649 }
2650 return node;
2651}
2652
2653TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
2654{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002655 if (mSwitchNestingLevel == 0)
2656 {
2657 error(loc, "default labels need to be inside switch statements", "default");
2658 recover();
2659 return nullptr;
2660 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02002661 TIntermCase *node = intermediate.addCase(nullptr, loc);
2662 if (node == nullptr)
2663 {
2664 error(loc, "erroneous default statement", "default");
2665 recover();
2666 return nullptr;
2667 }
2668 return node;
2669}
2670
Olli Etuahof6c694b2015-03-26 14:50:53 +02002671TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc,
2672 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02002673{
2674 if (child == nullptr)
2675 {
2676 return nullptr;
2677 }
2678
2679 switch (op)
2680 {
2681 case EOpLogicalNot:
2682 if (child->getBasicType() != EbtBool ||
2683 child->isMatrix() ||
2684 child->isArray() ||
2685 child->isVector())
2686 {
2687 return nullptr;
2688 }
2689 break;
2690 case EOpBitwiseNot:
2691 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
2692 child->isMatrix() ||
2693 child->isArray())
2694 {
2695 return nullptr;
2696 }
2697 break;
2698 case EOpPostIncrement:
2699 case EOpPreIncrement:
2700 case EOpPostDecrement:
2701 case EOpPreDecrement:
2702 case EOpNegative:
2703 case EOpPositive:
2704 if (child->getBasicType() == EbtStruct ||
Olli Etuahodca3e792015-03-26 13:24:04 +02002705 child->getBasicType() == EbtBool ||
Olli Etuaho69c11b52015-03-26 12:59:00 +02002706 child->isArray())
2707 {
2708 return nullptr;
2709 }
Olli Etuahodca3e792015-03-26 13:24:04 +02002710 // Operators for built-ins are already type checked against their prototype.
Olli Etuaho69c11b52015-03-26 12:59:00 +02002711 default:
2712 break;
2713 }
2714
Olli Etuahof6c694b2015-03-26 14:50:53 +02002715 return intermediate.addUnaryMath(op, child, loc, funcReturnType);
Olli Etuaho69c11b52015-03-26 12:59:00 +02002716}
2717
Olli Etuaho09b22472015-02-11 11:47:26 +02002718TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
2719{
Olli Etuahof6c694b2015-03-26 14:50:53 +02002720 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02002721 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02002722 {
2723 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
2724 recover();
2725 return child;
2726 }
2727 return node;
2728}
2729
2730TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
2731{
2732 if (lValueErrorCheck(loc, GetOperatorString(op), child))
2733 recover();
2734 return addUnaryMath(op, child, loc);
2735}
2736
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002737bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
Olli Etuahod6b14282015-03-17 14:31:35 +02002738 const TSourceLoc &loc)
2739{
2740 if (left->isArray() || right->isArray())
2741 {
Olli Etuahoe79904c2015-03-18 16:56:42 +02002742 if (shaderVersion < 300)
2743 {
2744 error(loc, "Invalid operation for arrays", GetOperatorString(op));
2745 return false;
2746 }
2747
2748 if (left->isArray() != right->isArray())
2749 {
2750 error(loc, "array / non-array mismatch", GetOperatorString(op));
2751 return false;
2752 }
2753
2754 switch (op)
2755 {
2756 case EOpEqual:
2757 case EOpNotEqual:
2758 case EOpAssign:
2759 case EOpInitialize:
2760 break;
2761 default:
2762 error(loc, "Invalid operation for arrays", GetOperatorString(op));
2763 return false;
2764 }
2765 if (left->getArraySize() != right->getArraySize())
2766 {
2767 error(loc, "array size mismatch", GetOperatorString(op));
2768 return false;
2769 }
Olli Etuahod6b14282015-03-17 14:31:35 +02002770 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002771
2772 // Check ops which require integer / ivec parameters
2773 bool isBitShift = false;
2774 switch (op)
2775 {
2776 case EOpBitShiftLeft:
2777 case EOpBitShiftRight:
2778 case EOpBitShiftLeftAssign:
2779 case EOpBitShiftRightAssign:
2780 // Unsigned can be bit-shifted by signed and vice versa, but we need to
2781 // check that the basic type is an integer type.
2782 isBitShift = true;
2783 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
2784 {
2785 return false;
2786 }
2787 break;
2788 case EOpBitwiseAnd:
2789 case EOpBitwiseXor:
2790 case EOpBitwiseOr:
2791 case EOpBitwiseAndAssign:
2792 case EOpBitwiseXorAssign:
2793 case EOpBitwiseOrAssign:
2794 // It is enough to check the type of only one operand, since later it
2795 // is checked that the operand types match.
2796 if (!IsInteger(left->getBasicType()))
2797 {
2798 return false;
2799 }
2800 break;
2801 default:
2802 break;
2803 }
2804
2805 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
2806 // So the basic type should usually match.
2807 if (!isBitShift && left->getBasicType() != right->getBasicType())
2808 {
2809 return false;
2810 }
2811
Olli Etuaho9dd217b2015-03-20 14:24:31 +02002812 // Check that type sizes match exactly on ops that require that.
Olli Etuahoff699002015-03-23 14:38:42 +02002813 // Also check restrictions for structs that contain arrays or samplers.
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002814 switch(op)
2815 {
2816 case EOpAssign:
2817 case EOpInitialize:
2818 case EOpEqual:
2819 case EOpNotEqual:
Olli Etuaho9dd217b2015-03-20 14:24:31 +02002820 // ESSL 1.00 sections 5.7, 5.8, 5.9
2821 if (shaderVersion < 300 && left->getType().isStructureContainingArrays())
2822 {
2823 error(loc, "undefined operation for structs containing arrays", GetOperatorString(op));
2824 return false;
2825 }
Olli Etuahoff699002015-03-23 14:38:42 +02002826 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
2827 // we interpret the spec so that this extends to structs containing samplers,
2828 // similarly to ESSL 1.00 spec.
2829 if ((shaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
2830 left->getType().isStructureContainingSamplers())
2831 {
2832 error(loc, "undefined operation for structs containing samplers", GetOperatorString(op));
2833 return false;
2834 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002835 case EOpLessThan:
2836 case EOpGreaterThan:
2837 case EOpLessThanEqual:
2838 case EOpGreaterThanEqual:
2839 if ((left->getNominalSize() != right->getNominalSize()) ||
2840 (left->getSecondarySize() != right->getSecondarySize()))
2841 {
2842 return false;
2843 }
2844 default:
2845 break;
2846 }
2847
Olli Etuahod6b14282015-03-17 14:31:35 +02002848 return true;
2849}
2850
Olli Etuahofc1806e2015-03-17 13:03:11 +02002851TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
2852 const TSourceLoc &loc)
2853{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002854 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02002855 return nullptr;
2856
Olli Etuahofc1806e2015-03-17 13:03:11 +02002857 switch (op)
2858 {
2859 case EOpEqual:
2860 case EOpNotEqual:
Olli Etuahofc1806e2015-03-17 13:03:11 +02002861 break;
2862 case EOpLessThan:
2863 case EOpGreaterThan:
2864 case EOpLessThanEqual:
2865 case EOpGreaterThanEqual:
Olli Etuahod6b14282015-03-17 14:31:35 +02002866 ASSERT(!left->isArray() && !right->isArray());
2867 if (left->isMatrix() || left->isVector() ||
Olli Etuahofc1806e2015-03-17 13:03:11 +02002868 left->getBasicType() == EbtStruct)
2869 {
2870 return nullptr;
2871 }
2872 break;
2873 case EOpLogicalOr:
2874 case EOpLogicalXor:
2875 case EOpLogicalAnd:
Olli Etuahod6b14282015-03-17 14:31:35 +02002876 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002877 if (left->getBasicType() != EbtBool ||
Olli Etuahod6b14282015-03-17 14:31:35 +02002878 left->isMatrix() || left->isVector())
Olli Etuahofc1806e2015-03-17 13:03:11 +02002879 {
2880 return nullptr;
2881 }
2882 break;
2883 case EOpAdd:
2884 case EOpSub:
2885 case EOpDiv:
2886 case EOpMul:
Olli Etuahod6b14282015-03-17 14:31:35 +02002887 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002888 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
2889 {
2890 return nullptr;
2891 }
2892 break;
2893 case EOpIMod:
Olli Etuahod6b14282015-03-17 14:31:35 +02002894 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002895 // Note that this is only for the % operator, not for mod()
2896 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
2897 {
2898 return nullptr;
2899 }
2900 break;
2901 // Note that for bitwise ops, type checking is done in promote() to
2902 // share code between ops and compound assignment
2903 default:
2904 break;
2905 }
2906
Olli Etuahofc1806e2015-03-17 13:03:11 +02002907 return intermediate.addBinaryMath(op, left, right, loc);
2908}
2909
Olli Etuaho09b22472015-02-11 11:47:26 +02002910TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right,
2911 const TSourceLoc &loc)
2912{
Olli Etuahofc1806e2015-03-17 13:03:11 +02002913 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02002914 if (node == 0)
2915 {
2916 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
2917 recover();
2918 return left;
2919 }
2920 return node;
2921}
2922
2923TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
2924 const TSourceLoc &loc)
2925{
Olli Etuahofc1806e2015-03-17 13:03:11 +02002926 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02002927 if (node == 0)
2928 {
2929 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
2930 recover();
2931 ConstantUnion *unionArray = new ConstantUnion[1];
2932 unionArray->setBConst(false);
2933 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), loc);
2934 }
2935 return node;
2936}
2937
Olli Etuahod6b14282015-03-17 14:31:35 +02002938TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
2939 const TSourceLoc &loc)
2940{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002941 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02002942 {
2943 return intermediate.addAssign(op, left, right, loc);
2944 }
2945 return nullptr;
2946}
2947
2948TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
2949 const TSourceLoc &loc)
2950{
2951 TIntermTyped *node = createAssign(op, left, right, loc);
2952 if (node == nullptr)
2953 {
2954 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
2955 recover();
2956 return left;
2957 }
2958 return node;
2959}
2960
Olli Etuaho49300862015-02-20 14:54:49 +02002961TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
2962{
2963 switch (op)
2964 {
2965 case EOpContinue:
2966 if (mLoopNestingLevel <= 0)
2967 {
2968 error(loc, "continue statement only allowed in loops", "");
2969 recover();
2970 }
2971 break;
2972 case EOpBreak:
Olli Etuaho53f076f2015-02-20 10:55:14 +02002973 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
Olli Etuaho49300862015-02-20 14:54:49 +02002974 {
Olli Etuaho53f076f2015-02-20 10:55:14 +02002975 error(loc, "break statement only allowed in loops and switch statements", "");
Olli Etuaho49300862015-02-20 14:54:49 +02002976 recover();
2977 }
2978 break;
2979 case EOpReturn:
2980 if (currentFunctionType->getBasicType() != EbtVoid)
2981 {
2982 error(loc, "non-void function must return a value", "return");
2983 recover();
2984 }
2985 break;
2986 default:
2987 // No checks for discard
2988 break;
2989 }
2990 return intermediate.addBranch(op, loc);
2991}
2992
2993TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
2994{
2995 ASSERT(op == EOpReturn);
2996 mFunctionReturnsValue = true;
2997 if (currentFunctionType->getBasicType() == EbtVoid)
2998 {
2999 error(loc, "void function cannot return a value", "return");
3000 recover();
3001 }
3002 else if (*currentFunctionType != returnValue->getType())
3003 {
3004 error(loc, "function return is not matching type:", "return");
3005 recover();
3006 }
3007 return intermediate.addBranch(op, returnValue, loc);
3008}
3009
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003010TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
3011 const TSourceLoc &loc, bool *fatalError)
3012{
3013 *fatalError = false;
3014 TOperator op = fnCall->getBuiltInOp();
3015 TIntermTyped *callNode = nullptr;
3016
3017 if (op != EOpNull)
3018 {
3019 //
3020 // Then this should be a constructor.
3021 // Don't go through the symbol table for constructors.
3022 // Their parameters will be verified algorithmically.
3023 //
3024 TType type(EbtVoid, EbpUndefined); // use this to get the type back
3025 if (!constructorErrorCheck(loc, node, *fnCall, op, &type))
3026 {
3027 //
3028 // It's a constructor, of type 'type'.
3029 //
3030 callNode = addConstructor(node, &type, op, fnCall, loc);
3031 }
Olli Etuaho72ba85b2015-03-04 14:23:26 +02003032
3033 if (callNode == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003034 {
3035 recover();
3036 callNode = intermediate.setAggregateOperator(nullptr, op, loc);
3037 }
3038 callNode->setType(type);
3039 }
3040 else
3041 {
3042 //
3043 // Not a constructor. Find it in the symbol table.
3044 //
3045 const TFunction* fnCandidate;
3046 bool builtIn;
3047 fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn);
3048 if (fnCandidate)
3049 {
3050 //
3051 // A declared function.
3052 //
3053 if (builtIn && !fnCandidate->getExtension().empty() &&
3054 extensionErrorCheck(loc, fnCandidate->getExtension()))
3055 {
3056 recover();
3057 }
3058 op = fnCandidate->getBuiltInOp();
3059 if (builtIn && op != EOpNull)
3060 {
3061 //
3062 // A function call mapped to a built-in operation.
3063 //
3064 if (fnCandidate->getParamCount() == 1)
3065 {
3066 //
3067 // Treat it like a built-in unary operator.
3068 //
Olli Etuahof6c694b2015-03-26 14:50:53 +02003069 callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003070 if (callNode == nullptr)
3071 {
3072 std::stringstream extraInfoStream;
3073 extraInfoStream << "built in unary operator function. Type: "
3074 << static_cast<TIntermTyped*>(node)->getCompleteString();
3075 std::string extraInfo = extraInfoStream.str();
3076 error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
3077 *fatalError = true;
3078 return nullptr;
3079 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003080 }
3081 else
3082 {
3083 TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc);
3084 aggregate->setType(fnCandidate->getReturnType());
3085 aggregate->setPrecisionFromChildren();
3086 callNode = aggregate;
3087
3088 // Some built-in functions have out parameters too.
3089 functionCallLValueErrorCheck(fnCandidate, aggregate);
3090 }
3091 }
3092 else
3093 {
3094 // This is a real function call
3095
3096 TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc);
3097 aggregate->setType(fnCandidate->getReturnType());
3098
3099 // this is how we know whether the given function is a builtIn function or a user defined function
3100 // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
3101 // if builtIn == true, it's definitely a builtIn function with EOpNull
3102 if (!builtIn)
3103 aggregate->setUserDefined();
3104 aggregate->setName(fnCandidate->getMangledName());
Corentin Wallez71d147f2015-02-11 11:15:24 -08003105 aggregate->setFunctionId(fnCandidate->getUniqueId());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003106
3107 // This needs to happen after the name is set
3108 if (builtIn)
3109 aggregate->setBuiltInFunctionPrecision();
3110
3111 callNode = aggregate;
3112
3113 functionCallLValueErrorCheck(fnCandidate, aggregate);
3114 }
3115 }
3116 else
3117 {
3118 // error message was put out by findFunction()
3119 // Put on a dummy node for error recovery
3120 ConstantUnion *unionArray = new ConstantUnion[1];
3121 unionArray->setFConst(0.0f);
3122 callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc);
3123 recover();
3124 }
3125 }
3126 delete fnCall;
3127 return callNode;
3128}
3129
Olli Etuaho49300862015-02-20 14:54:49 +02003130
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003131//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003132// Parse an array of strings using yyparse.
3133//
3134// Returns 0 for success.
3135//
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +00003136int PaParseStrings(size_t count, const char* const string[], const int length[],
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003137 TParseContext* context) {
3138 if ((count == 0) || (string == NULL))
3139 return 1;
3140
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003141 if (glslang_initialize(context))
3142 return 1;
3143
alokp@chromium.org408c45e2012-04-05 15:54:43 +00003144 int error = glslang_scan(count, string, length, context);
3145 if (!error)
3146 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003147
alokp@chromium.org73bc2982012-06-19 18:48:05 +00003148 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00003149
alokp@chromium.org6b495712012-06-29 00:06:58 +00003150 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003151}
3152
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003153
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00003154