blob: 6ed92ec83546e00d910869b187ad4985a3c9321e [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"
Dmitry Skiba01971112015-07-10 14:54:00 -040013#include "compiler/translator/Cache.h"
Olli Etuahoac5274d2015-02-20 10:19:08 +020014#include "compiler/translator/glslang.h"
15#include "compiler/translator/ValidateSwitch.h"
Olli Etuahob0c645e2015-05-12 14:25:36 +030016#include "compiler/translator/ValidateGlobalInitializer.h"
Olli Etuaho37ad4742015-04-27 13:18:50 +030017#include "compiler/translator/util.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
alokp@chromium.org8b851c62012-06-15 16:25:11 +000019///////////////////////////////////////////////////////////////////////
20//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021// Sub- vector and matrix fields
22//
23////////////////////////////////////////////////////////////////////////
24
25//
26// Look at a '.' field selector string and change it into offsets
27// for a vector.
28//
Jamie Madillb98c3a82015-07-23 14:26:04 -040029bool TParseContext::parseVectorFields(const TString &compString,
30 int vecSize,
31 TVectorFields &fields,
Arun Patole7e7e68d2015-05-22 12:02:25 +053032 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033{
Jamie Madillb98c3a82015-07-23 14:26:04 -040034 fields.num = (int)compString.size();
Arun Patole7e7e68d2015-05-22 12:02:25 +053035 if (fields.num > 4)
36 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000037 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000038 return false;
39 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000040
Jamie Madillb98c3a82015-07-23 14:26:04 -040041 enum
42 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000043 exyzw,
44 ergba,
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000045 estpq
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000046 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000047
Arun Patole7e7e68d2015-05-22 12:02:25 +053048 for (int i = 0; i < fields.num; ++i)
49 {
50 switch (compString[i])
51 {
Jamie Madillb98c3a82015-07-23 14:26:04 -040052 case 'x':
53 fields.offsets[i] = 0;
54 fieldSet[i] = exyzw;
55 break;
56 case 'r':
57 fields.offsets[i] = 0;
58 fieldSet[i] = ergba;
59 break;
60 case 's':
61 fields.offsets[i] = 0;
62 fieldSet[i] = estpq;
63 break;
64 case 'y':
65 fields.offsets[i] = 1;
66 fieldSet[i] = exyzw;
67 break;
68 case 'g':
69 fields.offsets[i] = 1;
70 fieldSet[i] = ergba;
71 break;
72 case 't':
73 fields.offsets[i] = 1;
74 fieldSet[i] = estpq;
75 break;
76 case 'z':
77 fields.offsets[i] = 2;
78 fieldSet[i] = exyzw;
79 break;
80 case 'b':
81 fields.offsets[i] = 2;
82 fieldSet[i] = ergba;
83 break;
84 case 'p':
85 fields.offsets[i] = 2;
86 fieldSet[i] = estpq;
87 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +053088
Jamie Madillb98c3a82015-07-23 14:26:04 -040089 case 'w':
90 fields.offsets[i] = 3;
91 fieldSet[i] = exyzw;
92 break;
93 case 'a':
94 fields.offsets[i] = 3;
95 fieldSet[i] = ergba;
96 break;
97 case 'q':
98 fields.offsets[i] = 3;
99 fieldSet[i] = estpq;
100 break;
101 default:
102 error(line, "illegal vector field selection", compString.c_str());
103 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000104 }
105 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000106
Arun Patole7e7e68d2015-05-22 12:02:25 +0530107 for (int i = 0; i < fields.num; ++i)
108 {
109 if (fields.offsets[i] >= vecSize)
110 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400111 error(line, "vector field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000112 return false;
113 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114
Arun Patole7e7e68d2015-05-22 12:02:25 +0530115 if (i > 0)
116 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400117 if (fieldSet[i] != fieldSet[i - 1])
Arun Patole7e7e68d2015-05-22 12:02:25 +0530118 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400119 error(line, "illegal - vector component fields not from the same set",
120 compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000121 return false;
122 }
123 }
124 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000126 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000127}
128
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129//
130// Look at a '.' field selector string and change it into offsets
131// for a matrix.
132//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400133bool TParseContext::parseMatrixFields(const TString &compString,
134 int matCols,
135 int matRows,
136 TMatrixFields &fields,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530137 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000139 fields.wholeRow = false;
140 fields.wholeCol = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400141 fields.row = -1;
142 fields.col = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143
Arun Patole7e7e68d2015-05-22 12:02:25 +0530144 if (compString.size() != 2)
145 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000146 error(line, "illegal length of matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000147 return false;
148 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149
Arun Patole7e7e68d2015-05-22 12:02:25 +0530150 if (compString[0] == '_')
151 {
152 if (compString[1] < '0' || compString[1] > '3')
153 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000154 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000155 return false;
156 }
157 fields.wholeCol = true;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400158 fields.col = compString[1] - '0';
Arun Patole7e7e68d2015-05-22 12:02:25 +0530159 }
160 else if (compString[1] == '_')
161 {
162 if (compString[0] < '0' || compString[0] > '3')
163 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000164 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000165 return false;
166 }
167 fields.wholeRow = true;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400168 fields.row = compString[0] - '0';
Arun Patole7e7e68d2015-05-22 12:02:25 +0530169 }
170 else
171 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400172 if (compString[0] < '0' || compString[0] > '3' || compString[1] < '0' ||
173 compString[1] > '3')
Arun Patole7e7e68d2015-05-22 12:02:25 +0530174 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000175 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000176 return false;
177 }
178 fields.row = compString[0] - '0';
179 fields.col = compString[1] - '0';
180 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181
Arun Patole7e7e68d2015-05-22 12:02:25 +0530182 if (fields.row >= matRows || fields.col >= matCols)
183 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000184 error(line, "matrix field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000185 return false;
186 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000188 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
191///////////////////////////////////////////////////////////////////////
192//
193// Errors
194//
195////////////////////////////////////////////////////////////////////////
196
197//
198// Track whether errors have occurred.
199//
200void TParseContext::recover()
201{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202}
203
204//
205// Used by flex/bison to output all syntax and parsing errors.
206//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530207void TParseContext::error(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400208 const char *reason,
209 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530210 const char *extraInfo)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000212 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400213 srcLoc.file = loc.first_file;
214 srcLoc.line = loc.first_line;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400215 mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216}
217
Arun Patole7e7e68d2015-05-22 12:02:25 +0530218void TParseContext::warning(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400219 const char *reason,
220 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530221 const char *extraInfo)
222{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000223 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400224 srcLoc.file = loc.first_file;
225 srcLoc.line = loc.first_line;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400226 mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000227}
228
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229//
230// Same error message for all places assignments don't work.
231//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530232void TParseContext::assignError(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 << "cannot convert from '" << right << "' to '" << left << "'";
236 std::string extraInfo = extraInfoStream.str();
237 error(line, "", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238}
239
240//
241// Same error message for all places unary operations don't work.
242//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530243void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000244{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000245 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400246 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type "
247 << operand << " (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000248 std::string extraInfo = extraInfoStream.str();
249 error(line, " wrong operand type", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250}
251
252//
253// Same error message for all binary operations don't work.
254//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400255void TParseContext::binaryOpError(const TSourceLoc &line,
256 const char *op,
257 TString left,
258 TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000260 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400261 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '"
262 << left << "' and a right operand of type '" << right
263 << "' (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000264 std::string extraInfo = extraInfoStream.str();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530265 error(line, " wrong operand types ", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266}
267
Jamie Madillb98c3a82015-07-23 14:26:04 -0400268bool TParseContext::precisionErrorCheck(const TSourceLoc &line,
269 TPrecision precision,
270 TBasicType type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530271{
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400272 if (!mChecksPrecisionErrors)
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000273 return false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400274 switch (type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530275 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400276 case EbtFloat:
277 if (precision == EbpUndefined)
278 {
279 error(line, "No precision specified for (float)", "");
280 return true;
281 }
282 break;
283 case EbtInt:
284 if (precision == EbpUndefined)
285 {
286 error(line, "No precision specified (int)", "");
287 return true;
288 }
289 break;
290 default:
291 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000292 }
293 return false;
294}
295
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296//
297// Both test and if necessary, spit out an error, to see if the node is really
298// an l-value that can be operated on this way.
299//
300// Returns true if the was an error.
301//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530302bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400304 TIntermSymbol *symNode = node->getAsSymbolNode();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530305 TIntermBinary *binaryNode = node->getAsBinaryNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306
Arun Patole7e7e68d2015-05-22 12:02:25 +0530307 if (binaryNode)
308 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000309 bool errorReturn;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310
Jamie Madillb98c3a82015-07-23 14:26:04 -0400311 switch (binaryNode->getOp())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530312 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400313 case EOpIndexDirect:
314 case EOpIndexIndirect:
315 case EOpIndexDirectStruct:
316 case EOpIndexDirectInterfaceBlock:
317 return lValueErrorCheck(line, op, binaryNode->getLeft());
318 case EOpVectorSwizzle:
319 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
320 if (!errorReturn)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530321 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400322 int offset[4] = {0, 0, 0, 0};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323
Jamie Madillb98c3a82015-07-23 14:26:04 -0400324 TIntermTyped *rightNode = binaryNode->getRight();
325 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
326
327 for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
328 p != aggrNode->getSequence()->end(); p++)
329 {
330 int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
331 offset[value]++;
332 if (offset[value] > 1)
333 {
334 error(line, " l-value of swizzle cannot have duplicate components", op);
335
336 return true;
337 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000338 }
339 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340
Jamie Madillb98c3a82015-07-23 14:26:04 -0400341 return errorReturn;
342 default:
343 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000344 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000345 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000347 return true;
348 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349
Arun Patole7e7e68d2015-05-22 12:02:25 +0530350 const char *symbol = 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000351 if (symNode != 0)
352 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353
Arun Patole7e7e68d2015-05-22 12:02:25 +0530354 const char *message = 0;
355 switch (node->getQualifier())
356 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400357 case EvqConst:
358 message = "can't modify a const";
359 break;
360 case EvqConstReadOnly:
361 message = "can't modify a const";
362 break;
363 case EvqAttribute:
364 message = "can't modify an attribute";
365 break;
366 case EvqFragmentIn:
367 message = "can't modify an input";
368 break;
369 case EvqVertexIn:
370 message = "can't modify an input";
371 break;
372 case EvqUniform:
373 message = "can't modify a uniform";
374 break;
375 case EvqVaryingIn:
376 message = "can't modify a varying";
377 break;
378 case EvqFragCoord:
379 message = "can't modify gl_FragCoord";
380 break;
381 case EvqFrontFacing:
382 message = "can't modify gl_FrontFacing";
383 break;
384 case EvqPointCoord:
385 message = "can't modify gl_PointCoord";
386 break;
387 default:
388 //
389 // Type that can't be written to?
390 //
391 if (node->getBasicType() == EbtVoid)
392 {
393 message = "can't modify void";
394 }
395 if (IsSampler(node->getBasicType()))
396 {
397 message = "can't modify a sampler";
398 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000399 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400
Arun Patole7e7e68d2015-05-22 12:02:25 +0530401 if (message == 0 && binaryNode == 0 && symNode == 0)
402 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000403 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000404
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000405 return true;
406 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000408 //
409 // Everything else is okay, no error.
410 //
411 if (message == 0)
412 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000414 //
415 // If we get here, we have an error and a message.
416 //
Arun Patole7e7e68d2015-05-22 12:02:25 +0530417 if (symNode)
418 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000419 std::stringstream extraInfoStream;
420 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
421 std::string extraInfo = extraInfoStream.str();
422 error(line, " l-value required", op, extraInfo.c_str());
423 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530424 else
425 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000426 std::stringstream extraInfoStream;
427 extraInfoStream << "(" << message << ")";
428 std::string extraInfo = extraInfoStream.str();
429 error(line, " l-value required", op, extraInfo.c_str());
430 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000432 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433}
434
435//
436// Both test, and if necessary spit out an error, to see if the node is really
437// a constant.
438//
439// Returns true if the was an error.
440//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530441bool TParseContext::constErrorCheck(TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000443 if (node->getQualifier() == EvqConst)
444 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000446 error(node->getLine(), "constant expression required", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000448 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449}
450
451//
452// Both test, and if necessary spit out an error, to see if the node is really
453// an integer.
454//
455// Returns true if the was an error.
456//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530457bool TParseContext::integerErrorCheck(TIntermTyped *node, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458{
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000459 if (node->isScalarInt())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000460 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000461
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000462 error(node->getLine(), "integer expression required", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000464 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465}
466
467//
468// Both test, and if necessary spit out an error, to see if we are currently
469// globally scoped.
470//
471// Returns true if the was an error.
472//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530473bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000475 if (global)
476 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000478 error(line, "only allowed at global scope", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000480 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481}
482
483//
484// For now, keep it simple: if it starts "gl_", it's reserved, independent
485// of scope. Except, if the symbol table is at the built-in push-level,
486// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000487// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
488// webgl shader.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489//
490// Returns true if there was an error.
491//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530492bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530494 static const char *reservedErrMsg = "reserved built-in name";
495 if (!symbolTable.atBuiltInLevel())
496 {
497 if (identifier.compare(0, 3, "gl_") == 0)
498 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000499 error(line, reservedErrMsg, "gl_");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000500 return true;
501 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530502 if (IsWebGLBasedSpec(mShaderSpec))
503 {
504 if (identifier.compare(0, 6, "webgl_") == 0)
505 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000506 error(line, reservedErrMsg, "webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000507 return true;
508 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530509 if (identifier.compare(0, 7, "_webgl_") == 0)
510 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000511 error(line, reservedErrMsg, "_webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000512 return true;
513 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530514 if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0)
515 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000516 error(line, reservedErrMsg, "css_");
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000517 return true;
518 }
alokp@chromium.org613ef312010-07-21 18:54:22 +0000519 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530520 if (identifier.find("__") != TString::npos)
521 {
522 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400523 "identifiers containing two consecutive underscores (__) are reserved as "
524 "possible future keywords",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530525 identifier.c_str());
daniel@transgaming.combeadd5d2012-04-12 02:35:31 +0000526 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000527 }
528 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000530 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531}
532
533//
534// Make sure there is enough data provided to the constructor to build
535// something of the type of the constructor. Also returns the type of
536// the constructor.
537//
538// Returns true if there was an error in construction.
539//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400540bool TParseContext::constructorErrorCheck(const TSourceLoc &line,
541 TIntermNode *node,
542 TFunction &function,
543 TOperator op,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530544 TType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000546 *type = function.getReturnType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000547
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000548 bool constructingMatrix = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400549 switch (op)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530550 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400551 case EOpConstructMat2:
552 case EOpConstructMat2x3:
553 case EOpConstructMat2x4:
554 case EOpConstructMat3x2:
555 case EOpConstructMat3:
556 case EOpConstructMat3x4:
557 case EOpConstructMat4x2:
558 case EOpConstructMat4x3:
559 case EOpConstructMat4:
560 constructingMatrix = true;
561 break;
562 default:
563 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000564 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000566 //
567 // Note: It's okay to have too many components available, but not okay to have unused
568 // arguments. 'full' will go to true when enough args have been seen. If we loop
569 // again, there is an extra argument, so 'overfull' will become true.
570 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000571
Jamie Madillb98c3a82015-07-23 14:26:04 -0400572 size_t size = 0;
573 bool constType = true;
574 bool full = false;
575 bool overFull = false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000576 bool matrixInMatrix = false;
577 bool arrayArg = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530578 for (size_t i = 0; i < function.getParamCount(); ++i)
579 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700580 const TConstParameter &param = function.getParam(i);
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000581 size += param.type->getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530582
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000583 if (constructingMatrix && param.type->isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000584 matrixInMatrix = true;
585 if (full)
586 overFull = true;
587 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
588 full = true;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000589 if (param.type->getQualifier() != EvqConst)
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000590 constType = false;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000591 if (param.type->isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000592 arrayArg = true;
593 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530594
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000595 if (constType)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000596 type->setQualifier(EvqConst);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597
Olli Etuaho376f1b52015-04-13 13:23:41 +0300598 if (type->isArray())
599 {
600 if (type->isUnsizedArray())
601 {
602 type->setArraySize(function.getParamCount());
603 }
604 else if (static_cast<size_t>(type->getArraySize()) != function.getParamCount())
605 {
606 error(line, "array constructor needs one argument per array element", "constructor");
607 return true;
608 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000609 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000610
Arun Patole7e7e68d2015-05-22 12:02:25 +0530611 if (arrayArg && op != EOpConstructStruct)
612 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000613 error(line, "constructing from a non-dereferenced array", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000614 return true;
615 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616
Arun Patole7e7e68d2015-05-22 12:02:25 +0530617 if (matrixInMatrix && !type->isArray())
618 {
619 if (function.getParamCount() != 1)
620 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400621 error(line, "constructing matrix from matrix can only take one argument",
622 "constructor");
623 return true;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000624 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000625 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626
Arun Patole7e7e68d2015-05-22 12:02:25 +0530627 if (overFull)
628 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000629 error(line, "too many arguments", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000630 return true;
631 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530632
Jamie Madillb98c3a82015-07-23 14:26:04 -0400633 if (op == EOpConstructStruct && !type->isArray() &&
634 type->getStruct()->fields().size() != function.getParamCount())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530635 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400636 error(line,
637 "Number of constructor parameters does not match the number of structure fields",
638 "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000639 return true;
640 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641
Arun Patole7e7e68d2015-05-22 12:02:25 +0530642 if (!type->isMatrix() || !matrixInMatrix)
643 {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000644 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
Arun Patole7e7e68d2015-05-22 12:02:25 +0530645 (op == EOpConstructStruct && size < type->getObjectSize()))
646 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000647 error(line, "not enough data provided for construction", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000648 return true;
649 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000650 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651
daniel@transgaming.com0b53fc02011-03-09 15:12:12 +0000652 TIntermTyped *typed = node ? node->getAsTyped() : 0;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530653 if (typed == 0)
654 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000655 error(line, "constructor argument does not have a type", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000656 return true;
657 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530658 if (op != EOpConstructStruct && IsSampler(typed->getBasicType()))
659 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000660 error(line, "cannot convert a sampler", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000661 return true;
662 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530663 if (typed->getBasicType() == EbtVoid)
664 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000665 error(line, "cannot convert a void", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000666 return true;
667 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000669 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000670}
671
Jamie Madillb98c3a82015-07-23 14:26:04 -0400672// This function checks to see if a void variable has been declared and raise an error message for
673// such a case
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000674//
675// returns true in case of an error
676//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400677bool TParseContext::voidErrorCheck(const TSourceLoc &line,
678 const TString &identifier,
679 const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300681 if (type == EbtVoid)
682 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000683 error(line, "illegal use of type 'void'", identifier.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000684 return true;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300685 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000687 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688}
689
Jamie Madillb98c3a82015-07-23 14:26:04 -0400690// This function checks to see if the node (for the expression) contains a scalar boolean expression
691// or not
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692//
693// returns true in case of an error
694//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530695bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TIntermTyped *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000696{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530697 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
698 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000699 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000700 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530701 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000703 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704}
705
Jamie Madillb98c3a82015-07-23 14:26:04 -0400706// This function checks to see if the node (for the expression) contains a scalar boolean expression
707// or not
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708//
709// returns true in case of an error
710//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530711bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TPublicType &pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000712{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530713 if (pType.type != EbtBool || pType.isAggregate())
714 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000715 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000716 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530717 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000719 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000720}
721
Jamie Madillb98c3a82015-07-23 14:26:04 -0400722bool TParseContext::samplerErrorCheck(const TSourceLoc &line,
723 const TPublicType &pType,
724 const char *reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000725{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530726 if (pType.type == EbtStruct)
727 {
728 if (containsSampler(*pType.userDef))
729 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000730 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530731
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000732 return true;
733 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530734
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000735 return false;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530736 }
737 else if (IsSampler(pType.type))
738 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000739 error(line, reason, getBasicString(pType.type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000741 return true;
742 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000744 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000745}
746
Arun Patole7e7e68d2015-05-22 12:02:25 +0530747bool TParseContext::locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400748{
749 if (pType.layoutQualifier.location != -1)
750 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400751 error(line, "location must only be specified for a single input or output variable",
752 "location");
Jamie Madill0bd18df2013-06-20 11:55:52 -0400753 return true;
754 }
755
756 return false;
757}
758
Jamie Madillb98c3a82015-07-23 14:26:04 -0400759bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line,
760 TQualifier qualifier,
761 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000762{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400763 if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct &&
764 IsSampler(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530765 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000766 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000767 return true;
768 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000770 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000771}
772
Arun Patole7e7e68d2015-05-22 12:02:25 +0530773bool TParseContext::containsSampler(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000774{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000775 if (IsSampler(type.getBasicType()))
776 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000777
Arun Patole7e7e68d2015-05-22 12:02:25 +0530778 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
779 {
780 const TFieldList &fields = type.getStruct()->fields();
781 for (unsigned int i = 0; i < fields.size(); ++i)
782 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400783 if (containsSampler(*fields[i]->type()))
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000784 return true;
785 }
786 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000787
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000788 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000789}
790
791//
792// Do size checking for an array type's size.
793//
794// Returns true if there was an error.
795//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530796bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530798 TIntermConstantUnion *constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000799
Olli Etuahoe7847b02015-03-16 11:56:12 +0200800 if (constant == nullptr || !constant->isScalarInt())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000801 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000802 error(line, "array size must be a constant integer expression", "");
Olli Etuahoe7847b02015-03-16 11:56:12 +0200803 size = 1;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000804 return true;
805 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806
Nicolas Capens906744a2014-06-06 15:18:07 -0400807 unsigned int unsignedSize = 0;
808
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000809 if (constant->getBasicType() == EbtUInt)
810 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400811 unsignedSize = constant->getUConst(0);
Jamie Madillb98c3a82015-07-23 14:26:04 -0400812 size = static_cast<int>(unsignedSize);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000813 }
814 else
815 {
816 size = constant->getIConst(0);
817
Nicolas Capens906744a2014-06-06 15:18:07 -0400818 if (size < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000819 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400820 error(line, "array size must be non-negative", "");
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000821 size = 1;
822 return true;
823 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400824
825 unsignedSize = static_cast<unsigned int>(size);
826 }
827
828 if (size == 0)
829 {
830 error(line, "array size must be greater than zero", "");
831 size = 1;
832 return true;
833 }
834
835 // The size of arrays is restricted here to prevent issues further down the
836 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
837 // 4096 registers so this should be reasonable even for aggressively optimizable code.
838 const unsigned int sizeLimit = 65536;
839
840 if (unsignedSize > sizeLimit)
841 {
842 error(line, "array size too large", "");
843 size = 1;
844 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000845 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000846
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000847 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000848}
849
850//
851// See if this qualifier can be an array.
852//
853// Returns true if there is an error.
854//
Olli Etuaho3739d232015-04-08 12:23:44 +0300855bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000856{
Olli Etuaho3739d232015-04-08 12:23:44 +0300857 if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) ||
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400858 (type.qualifier == EvqConst && mShaderVersion < 300))
Olli Etuaho3739d232015-04-08 12:23:44 +0300859 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400860 error(line, "cannot declare arrays of this qualifier",
861 TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000862 return true;
863 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000864
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000865 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000866}
867
868//
869// See if this type can be an array.
870//
871// Returns true if there is an error.
872//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530873bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000875 //
876 // Can the type be an array?
877 //
Jamie Madill06145232015-05-13 13:10:01 -0400878 if (type.array)
879 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000880 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000881 return true;
882 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000883
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000884 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000885}
886
887//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000888// Enforce non-initializer type/qualifier rules.
889//
890// Returns true if there was an error.
891//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400892bool TParseContext::nonInitErrorCheck(const TSourceLoc &line,
893 const TString &identifier,
894 TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000895{
Olli Etuaho3739d232015-04-08 12:23:44 +0300896 ASSERT(type != nullptr);
897 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000898 {
899 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +0300900 type->qualifier = EvqTemporary;
901
902 // Generate informative error messages for ESSL1.
903 // In ESSL3 arrays and structures containing arrays can be constant.
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400904 if (mShaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000905 {
Arun Patole7e7e68d2015-05-22 12:02:25 +0530906 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400907 "structures containing arrays may not be declared constant since they cannot be "
908 "initialized",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530909 identifier.c_str());
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000910 }
911 else
912 {
913 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
914 }
915
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000916 return true;
917 }
Olli Etuaho376f1b52015-04-13 13:23:41 +0300918 if (type->isUnsizedArray())
919 {
920 error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
921 return true;
922 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000923 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924}
925
Olli Etuaho2935c582015-04-08 14:32:06 +0300926// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927// and update the symbol table.
928//
Olli Etuaho2935c582015-04-08 14:32:06 +0300929// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400931bool TParseContext::declareVariable(const TSourceLoc &line,
932 const TString &identifier,
933 const TType &type,
Olli Etuaho2935c582015-04-08 14:32:06 +0300934 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935{
Olli Etuaho2935c582015-04-08 14:32:06 +0300936 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000937
Olli Etuaho2935c582015-04-08 14:32:06 +0300938 bool needsReservedErrorCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000939
Olli Etuaho2935c582015-04-08 14:32:06 +0300940 // gl_LastFragData may be redeclared with a new precision qualifier
941 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
942 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400943 const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
944 symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
Olli Etuaho2935c582015-04-08 14:32:06 +0300945 if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst())
946 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400947 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
Olli Etuaho2935c582015-04-08 14:32:06 +0300948 {
949 needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
950 }
951 }
952 else
953 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400954 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
955 identifier.c_str());
Olli Etuaho2935c582015-04-08 14:32:06 +0300956 return false;
957 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000958 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959
Olli Etuaho2935c582015-04-08 14:32:06 +0300960 if (needsReservedErrorCheck && reservedErrorCheck(line, identifier))
961 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000962
Olli Etuaho2935c582015-04-08 14:32:06 +0300963 (*variable) = new TVariable(&identifier, type);
964 if (!symbolTable.declare(*variable))
965 {
966 error(line, "redefinition", identifier.c_str());
Jamie Madill1a4b1b32015-07-23 18:27:13 -0400967 *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +0300968 return false;
969 }
970
971 if (voidErrorCheck(line, identifier, type.getBasicType()))
972 return false;
973
974 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975}
976
Jamie Madillb98c3a82015-07-23 14:26:04 -0400977bool TParseContext::paramErrorCheck(const TSourceLoc &line,
978 TQualifier qualifier,
979 TQualifier paramQualifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530980 TType *type)
981{
982 if (qualifier != EvqConst && qualifier != EvqTemporary)
983 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000984 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000985 return true;
986 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530987 if (qualifier == EvqConst && paramQualifier != EvqIn)
988 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400989 error(line, "qualifier not allowed with ", getQualifierString(qualifier),
990 getQualifierString(paramQualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000991 return true;
992 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000994 if (qualifier == EvqConst)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000995 type->setQualifier(EvqConstReadOnly);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000996 else
alokp@chromium.org58e54292010-08-24 21:40:03 +0000997 type->setQualifier(paramQualifier);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000998
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000999 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001000}
1001
Arun Patole7e7e68d2015-05-22 12:02:25 +05301002bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString &extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001003{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001004 const TExtensionBehavior &extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001005 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
Arun Patole7e7e68d2015-05-22 12:02:25 +05301006 if (iter == extBehavior.end())
1007 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001008 error(line, "extension", extension.c_str(), "is not supported");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001009 return true;
1010 }
zmo@google.comf5450912011-09-09 01:37:19 +00001011 // In GLSL ES, an extension's default behavior is "disable".
Arun Patole7e7e68d2015-05-22 12:02:25 +05301012 if (iter->second == EBhDisable || iter->second == EBhUndefined)
1013 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001014 error(line, "extension", extension.c_str(), "is disabled");
1015 return true;
1016 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301017 if (iter->second == EBhWarn)
1018 {
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001019 warning(line, "extension", extension.c_str(), "is being used");
alokp@chromium.org8815d7f2010-09-09 17:30:03 +00001020 return false;
1021 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001022
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001023 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001024}
1025
Jamie Madillb98c3a82015-07-23 14:26:04 -04001026// These checks are common for all declarations starting a declarator list, and declarators that
1027// follow an empty declaration.
Olli Etuahofa33d582015-04-09 14:33:12 +03001028//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001029bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
1030 const TSourceLoc &identifierLocation)
Jamie Madilla5efff92013-06-06 11:56:47 -04001031{
Olli Etuahofa33d582015-04-09 14:33:12 +03001032 switch (publicType.qualifier)
1033 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001034 case EvqVaryingIn:
1035 case EvqVaryingOut:
1036 case EvqAttribute:
1037 case EvqVertexIn:
1038 case EvqFragmentOut:
1039 if (publicType.type == EbtStruct)
1040 {
1041 error(identifierLocation, "cannot be used with a structure",
1042 getQualifierString(publicType.qualifier));
1043 return true;
1044 }
Olli Etuahofa33d582015-04-09 14:33:12 +03001045
Jamie Madillb98c3a82015-07-23 14:26:04 -04001046 default:
1047 break;
Olli Etuahofa33d582015-04-09 14:33:12 +03001048 }
1049
Jamie Madillb98c3a82015-07-23 14:26:04 -04001050 if (publicType.qualifier != EvqUniform &&
1051 samplerErrorCheck(identifierLocation, publicType, "samplers must be uniform"))
Olli Etuahofa33d582015-04-09 14:33:12 +03001052 {
Jamie Madilla5efff92013-06-06 11:56:47 -04001053 return true;
Olli Etuahofa33d582015-04-09 14:33:12 +03001054 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001055
1056 // check for layout qualifier issues
1057 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
1058
1059 if (layoutQualifier.matrixPacking != EmpUnspecified)
1060 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001061 error(identifierLocation, "layout qualifier",
1062 getMatrixPackingString(layoutQualifier.matrixPacking),
Olli Etuahofa33d582015-04-09 14:33:12 +03001063 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -04001064 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001065 }
1066
1067 if (layoutQualifier.blockStorage != EbsUnspecified)
1068 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001069 error(identifierLocation, "layout qualifier",
1070 getBlockStorageString(layoutQualifier.blockStorage),
Olli Etuahofa33d582015-04-09 14:33:12 +03001071 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -04001072 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001073 }
1074
Olli Etuahofa33d582015-04-09 14:33:12 +03001075 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut &&
1076 layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001077 {
Jamie Madill51a53c72013-06-19 09:24:43 -04001078 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001079 }
1080
1081 return false;
1082}
1083
Jamie Madillb98c3a82015-07-23 14:26:04 -04001084bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location,
1085 const TLayoutQualifier &layoutQualifier)
Jamie Madilla5efff92013-06-06 11:56:47 -04001086{
1087 if (layoutQualifier.location != -1)
1088 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001089 error(location, "invalid layout qualifier:", "location",
1090 "only valid on program inputs and outputs");
Jamie Madilla5efff92013-06-06 11:56:47 -04001091 return true;
1092 }
1093
1094 return false;
1095}
1096
Jamie Madillb98c3a82015-07-23 14:26:04 -04001097bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
1098 TIntermAggregate *aggregate)
Olli Etuahob6e07a62015-02-16 12:22:10 +02001099{
1100 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
1101 {
1102 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
1103 if (qual == EvqOut || qual == EvqInOut)
1104 {
1105 TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped();
1106 if (lValueErrorCheck(node->getLine(), "assign", node))
1107 {
1108 error(node->getLine(),
Jamie Madillb98c3a82015-07-23 14:26:04 -04001109 "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
Olli Etuahob6e07a62015-02-16 12:22:10 +02001110 recover();
1111 return true;
1112 }
1113 }
1114 }
1115 return false;
1116}
1117
Jamie Madillb98c3a82015-07-23 14:26:04 -04001118void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier,
1119 const TSourceLoc &invariantLocation)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001120{
1121 if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut)
1122 {
1123 error(invariantLocation, "Only out variables can be invariant.", "invariant");
1124 recover();
1125 }
1126}
1127
Arun Patole7e7e68d2015-05-22 12:02:25 +05301128bool TParseContext::supportsExtension(const char *extension)
zmo@google.com09c323a2011-08-12 18:22:25 +00001129{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001130 const TExtensionBehavior &extbehavior = extensionBehavior();
alokp@chromium.org73bc2982012-06-19 18:48:05 +00001131 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
1132 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001133}
1134
Arun Patole7e7e68d2015-05-22 12:02:25 +05301135bool TParseContext::isExtensionEnabled(const char *extension) const
Jamie Madill5d287f52013-07-12 15:38:19 -04001136{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001137 const TExtensionBehavior &extbehavior = extensionBehavior();
Shannon Woodsa49a9bf2013-08-02 17:23:14 -04001138 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
Jamie Madill5d287f52013-07-12 15:38:19 -04001139
1140 if (iter == extbehavior.end())
1141 {
1142 return false;
1143 }
1144
1145 return (iter->second == EBhEnable || iter->second == EBhRequire);
1146}
1147
Jamie Madillb98c3a82015-07-23 14:26:04 -04001148void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
1149 const char *extName,
1150 const char *behavior)
Jamie Madill075edd82013-07-08 13:30:19 -04001151{
1152 pp::SourceLocation srcLoc;
1153 srcLoc.file = loc.first_file;
1154 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001155 mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
Jamie Madill075edd82013-07-08 13:30:19 -04001156}
1157
Jamie Madillb98c3a82015-07-23 14:26:04 -04001158void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
1159 const char *name,
1160 const char *value,
1161 bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -04001162{
1163 pp::SourceLocation srcLoc;
1164 srcLoc.file = loc.first_file;
1165 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001166 mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -04001167}
1168
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001169/////////////////////////////////////////////////////////////////////////////////
1170//
1171// Non-Errors.
1172//
1173/////////////////////////////////////////////////////////////////////////////////
1174
Jamie Madill5c097022014-08-20 16:38:32 -04001175const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1176 const TString *name,
1177 const TSymbol *symbol)
1178{
1179 const TVariable *variable = NULL;
1180
1181 if (!symbol)
1182 {
1183 error(location, "undeclared identifier", name->c_str());
1184 recover();
1185 }
1186 else if (!symbol->isVariable())
1187 {
1188 error(location, "variable expected", name->c_str());
1189 recover();
1190 }
1191 else
1192 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001193 variable = static_cast<const TVariable *>(symbol);
Jamie Madill5c097022014-08-20 16:38:32 -04001194
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001195 if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
Jamie Madill5c097022014-08-20 16:38:32 -04001196 !variable->getExtension().empty() &&
1197 extensionErrorCheck(location, variable->getExtension()))
1198 {
1199 recover();
1200 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001201
1202 // Reject shaders using both gl_FragData and gl_FragColor
1203 TQualifier qualifier = variable->getType().getQualifier();
1204 if (qualifier == EvqFragData)
1205 {
1206 mUsesFragData = true;
1207 }
1208 else if (qualifier == EvqFragColor)
1209 {
1210 mUsesFragColor = true;
1211 }
1212
1213 // This validation is not quite correct - it's only an error to write to
1214 // both FragData and FragColor. For simplicity, and because users shouldn't
1215 // be rewarded for reading from undefined varaibles, return an error
1216 // if they are both referenced, rather than assigned.
1217 if (mUsesFragData && mUsesFragColor)
1218 {
1219 error(location, "cannot use both gl_FragData and gl_FragColor", name->c_str());
1220 recover();
1221 }
Jamie Madill5c097022014-08-20 16:38:32 -04001222 }
1223
1224 if (!variable)
1225 {
1226 TType type(EbtFloat, EbpUndefined);
1227 TVariable *fakeVariable = new TVariable(name, type);
1228 symbolTable.declare(fakeVariable);
1229 variable = fakeVariable;
1230 }
1231
1232 return variable;
1233}
1234
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001235//
1236// Look up a function name in the symbol table, and make sure it is a function.
1237//
1238// Return the function symbol if found, otherwise 0.
1239//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001240const TFunction *TParseContext::findFunction(const TSourceLoc &line,
1241 TFunction *call,
1242 int inputShaderVersion,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301243 bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001244{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001245 // First find by unmangled name to check whether the function name has been
1246 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001247 // If a function is found, check for one with a matching argument list.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301248 const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
1249 if (symbol == 0 || symbol->isFunction())
1250 {
Austin Kinross3ae64652015-01-26 15:51:39 -08001251 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001252 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001253
Arun Patole7e7e68d2015-05-22 12:02:25 +05301254 if (symbol == 0)
1255 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001256 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001257 return 0;
1258 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259
Arun Patole7e7e68d2015-05-22 12:02:25 +05301260 if (!symbol->isFunction())
1261 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001262 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001263 return 0;
1264 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001265
Jamie Madillb98c3a82015-07-23 14:26:04 -04001266 return static_cast<const TFunction *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001267}
1268
1269//
1270// Initializers show up in several places in the grammar. Have one set of
1271// code to handle them here.
1272//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001273// Returns true on error, false if no error
1274//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001275bool TParseContext::executeInitializer(const TSourceLoc &line,
1276 const TString &identifier,
1277 const TPublicType &pType,
1278 TIntermTyped *initializer,
1279 TIntermNode **intermNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001280{
Olli Etuahoe7847b02015-03-16 11:56:12 +02001281 ASSERT(intermNode != nullptr);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001282 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283
Olli Etuaho2935c582015-04-08 14:32:06 +03001284 TVariable *variable = nullptr;
Olli Etuaho376f1b52015-04-13 13:23:41 +03001285 if (type.isUnsizedArray())
1286 {
1287 type.setArraySize(initializer->getArraySize());
1288 }
Olli Etuaho2935c582015-04-08 14:32:06 +03001289 if (!declareVariable(line, identifier, type, &variable))
1290 {
1291 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001292 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001293
Olli Etuahob0c645e2015-05-12 14:25:36 +03001294 bool globalInitWarning = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001295 if (symbolTable.atGlobalLevel() &&
1296 !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
Olli Etuahob0c645e2015-05-12 14:25:36 +03001297 {
1298 // Error message does not completely match behavior with ESSL 1.00, but
1299 // we want to steer developers towards only using constant expressions.
1300 error(line, "global variable initializers must be constant expressions", "=");
1301 return true;
1302 }
1303 if (globalInitWarning)
1304 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001305 warning(
1306 line,
1307 "global variable initializers should be constant expressions "
1308 "(uniforms and globals are allowed in global initializers for legacy compatibility)",
1309 "=");
Olli Etuahob0c645e2015-05-12 14:25:36 +03001310 }
1311
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001312 //
1313 // identifier must be of type constant, a global, or a temporary
1314 //
1315 TQualifier qualifier = variable->getType().getQualifier();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301316 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
1317 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001318 error(line, " cannot initialize this type of qualifier ",
1319 variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001320 return true;
1321 }
1322 //
1323 // test for and propagate constant
1324 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001325
Arun Patole7e7e68d2015-05-22 12:02:25 +05301326 if (qualifier == EvqConst)
1327 {
1328 if (qualifier != initializer->getType().getQualifier())
1329 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001330 std::stringstream extraInfoStream;
1331 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1332 std::string extraInfo = extraInfoStream.str();
1333 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001334 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001335 return true;
1336 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301337 if (type != initializer->getType())
1338 {
1339 error(line, " non-matching types for const initializer ",
Jamie Madillb98c3a82015-07-23 14:26:04 -04001340 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001341 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001342 return true;
1343 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301344 if (initializer->getAsConstantUnion())
1345 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001346 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
Arun Patole7e7e68d2015-05-22 12:02:25 +05301347 }
1348 else if (initializer->getAsSymbolNode())
1349 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001350 const TSymbol *symbol =
1351 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1352 const TVariable *tVar = static_cast<const TVariable *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353
Arun Patole7e7e68d2015-05-22 12:02:25 +05301354 TConstantUnion *constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001355 variable->shareConstPointer(constArray);
Arun Patole7e7e68d2015-05-22 12:02:25 +05301356 }
1357 else
1358 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001359 std::stringstream extraInfoStream;
1360 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1361 std::string extraInfo = extraInfoStream.str();
1362 error(line, " cannot assign to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001363 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001364 return true;
1365 }
1366 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001367
1368 if (qualifier != EvqConst)
1369 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001370 TIntermSymbol *intermSymbol = intermediate.addSymbol(
1371 variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001372 *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
1373 if (*intermNode == nullptr)
1374 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001375 assignError(line, "=", intermSymbol->getCompleteString(),
1376 initializer->getCompleteString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001377 return true;
1378 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001379 }
1380 else
1381 {
1382 *intermNode = nullptr;
1383 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001384
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001385 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001386}
1387
Arun Patole7e7e68d2015-05-22 12:02:25 +05301388bool TParseContext::areAllChildConst(TIntermAggregate *aggrNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001389{
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001390 ASSERT(aggrNode != NULL);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001391 if (!aggrNode->isConstructor())
1392 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001393
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001394 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001395
Arun Patole7e7e68d2015-05-22 12:02:25 +05301396 // check if all the child nodes are constants so that they can be inserted into
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001397 // the parent node
Jamie Madillb98c3a82015-07-23 14:26:04 -04001398 TIntermSequence *sequence = aggrNode->getSequence();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301399 for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p)
1400 {
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001401 if (!(*p)->getAsTyped()->getAsConstantUnion())
1402 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001403 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001404
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001405 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001406}
1407
Jamie Madillb98c3a82015-07-23 14:26:04 -04001408TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
1409 bool invariant,
1410 TLayoutQualifier layoutQualifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301411 const TPublicType &typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001412{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001413 TPublicType returnType = typeSpecifier;
1414 returnType.qualifier = qualifier;
1415 returnType.invariant = invariant;
Jamie Madilla5efff92013-06-06 11:56:47 -04001416 returnType.layoutQualifier = layoutQualifier;
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001417
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001418 if (mShaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001419 {
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001420 if (typeSpecifier.array)
1421 {
1422 error(typeSpecifier.line, "not supported", "first-class array");
1423 recover();
1424 returnType.clearArrayness();
1425 }
1426
Jamie Madillb98c3a82015-07-23 14:26:04 -04001427 if (qualifier == EvqAttribute &&
1428 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001429 {
1430 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1431 recover();
1432 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001433
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001434 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1435 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1436 {
1437 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1438 recover();
1439 }
1440 }
1441 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001442 {
Olli Etuahoabb0c382015-07-13 12:01:12 +03001443 if (!layoutQualifier.isEmpty())
1444 {
1445 if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout"))
1446 {
1447 recover();
1448 }
1449 }
Jamie Madillb120eac2013-06-12 14:08:13 -04001450 switch (qualifier)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001451 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001452 case EvqSmoothIn:
1453 case EvqSmoothOut:
1454 case EvqVertexOut:
1455 case EvqFragmentIn:
1456 case EvqCentroidOut:
1457 case EvqCentroidIn:
1458 if (typeSpecifier.type == EbtBool)
1459 {
1460 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1461 recover();
1462 }
1463 if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
1464 {
1465 error(typeSpecifier.line, "must use 'flat' interpolation here",
1466 getQualifierString(qualifier));
1467 recover();
1468 }
1469 break;
Jamie Madill19571812013-08-12 15:26:34 -07001470
Jamie Madillb98c3a82015-07-23 14:26:04 -04001471 case EvqVertexIn:
1472 case EvqFragmentOut:
1473 case EvqFlatIn:
1474 case EvqFlatOut:
1475 if (typeSpecifier.type == EbtBool)
1476 {
1477 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1478 recover();
1479 }
1480 break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001481
Jamie Madillb98c3a82015-07-23 14:26:04 -04001482 default:
1483 break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001484 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001485 }
1486
1487 return returnType;
1488}
1489
Olli Etuahofa33d582015-04-09 14:33:12 +03001490TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
1491 const TSourceLoc &identifierOrTypeLocation,
1492 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001493{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001494 TIntermSymbol *symbol =
1495 intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001496
Olli Etuahobab4c082015-04-24 16:38:49 +03001497 bool emptyDeclaration = (identifier == "");
Olli Etuahofa33d582015-04-09 14:33:12 +03001498
Olli Etuahobab4c082015-04-24 16:38:49 +03001499 mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
1500
1501 if (emptyDeclaration)
1502 {
1503 if (publicType.isUnsizedArray())
1504 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001505 // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
1506 // error. It is assumed that this applies to empty declarations as well.
1507 error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
1508 identifier.c_str());
Olli Etuahobab4c082015-04-24 16:38:49 +03001509 }
1510 }
1511 else
Jamie Madill60ed9812013-06-06 11:56:46 -04001512 {
Olli Etuahofa33d582015-04-09 14:33:12 +03001513 if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001514 recover();
1515
Olli Etuaho376f1b52015-04-13 13:23:41 +03001516 if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001517 recover();
1518
Olli Etuaho2935c582015-04-08 14:32:06 +03001519 TVariable *variable = nullptr;
Olli Etuahofa33d582015-04-09 14:33:12 +03001520 if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001521 recover();
1522
1523 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001524 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001525 }
1526
Olli Etuahoe7847b02015-03-16 11:56:12 +02001527 return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001528}
1529
Olli Etuahoe7847b02015-03-16 11:56:12 +02001530TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
1531 const TSourceLoc &identifierLocation,
1532 const TString &identifier,
1533 const TSourceLoc &indexLocation,
1534 TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001535{
Olli Etuahofa33d582015-04-09 14:33:12 +03001536 mDeferredSingleDeclarationErrorCheck = false;
1537
1538 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001539 recover();
1540
Olli Etuaho376f1b52015-04-13 13:23:41 +03001541 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001542 recover();
1543
Jamie Madillb98c3a82015-07-23 14:26:04 -04001544 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1545 arrayQualifierErrorCheck(indexLocation, publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001546 {
1547 recover();
1548 }
1549
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001550 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001551
1552 int size;
1553 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1554 {
1555 recover();
1556 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001557 // Make the type an array even if size check failed.
1558 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1559 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001560
Olli Etuaho2935c582015-04-08 14:32:06 +03001561 TVariable *variable = nullptr;
1562 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001563 recover();
1564
Olli Etuahoe7847b02015-03-16 11:56:12 +02001565 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001566 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001567 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001568
Olli Etuahoe7847b02015-03-16 11:56:12 +02001569 return intermediate.makeAggregate(symbol, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001570}
1571
Jamie Madill06145232015-05-13 13:10:01 -04001572TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
Olli Etuahoe7847b02015-03-16 11:56:12 +02001573 const TSourceLoc &identifierLocation,
1574 const TString &identifier,
1575 const TSourceLoc &initLocation,
1576 TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001577{
Olli Etuahofa33d582015-04-09 14:33:12 +03001578 mDeferredSingleDeclarationErrorCheck = false;
1579
1580 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001581 recover();
1582
Olli Etuahoe7847b02015-03-16 11:56:12 +02001583 TIntermNode *intermNode = nullptr;
1584 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill60ed9812013-06-06 11:56:46 -04001585 {
1586 //
1587 // Build intermediate representation
1588 //
Olli Etuahoe7847b02015-03-16 11:56:12 +02001589 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001590 }
1591 else
1592 {
1593 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001594 return nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001595 }
1596}
1597
Jamie Madillb98c3a82015-07-23 14:26:04 -04001598TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
1599 TPublicType &publicType,
1600 const TSourceLoc &identifierLocation,
1601 const TString &identifier,
1602 const TSourceLoc &indexLocation,
1603 TIntermTyped *indexExpression,
1604 const TSourceLoc &initLocation,
1605 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001606{
1607 mDeferredSingleDeclarationErrorCheck = false;
1608
1609 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1610 recover();
1611
Jamie Madillb98c3a82015-07-23 14:26:04 -04001612 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1613 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001614 {
1615 recover();
1616 }
1617
1618 TPublicType arrayType(publicType);
1619
Olli Etuaho376f1b52015-04-13 13:23:41 +03001620 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001621 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1622 // the initializer.
1623 if (indexExpression != nullptr &&
1624 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001625 {
1626 recover();
1627 }
1628 // Make the type an array even if size check failed.
1629 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1630 arrayType.setArraySize(size);
1631
1632 // initNode will correspond to the whole of "type b[n] = initializer".
1633 TIntermNode *initNode = nullptr;
1634 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1635 {
1636 return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
1637 }
1638 else
1639 {
1640 recover();
1641 return nullptr;
1642 }
1643}
1644
Olli Etuahoe7847b02015-03-16 11:56:12 +02001645TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
Jamie Madill47e3ec02014-08-20 16:38:33 -04001646 const TSourceLoc &identifierLoc,
1647 const TString *identifier,
1648 const TSymbol *symbol)
1649{
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001650 // invariant declaration
Jamie Madill47e3ec02014-08-20 16:38:33 -04001651 if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
1652 {
1653 recover();
1654 }
1655
1656 if (!symbol)
1657 {
1658 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
1659 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001660 return nullptr;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001661 }
1662 else
1663 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001664 const TString kGlFrontFacing("gl_FrontFacing");
1665 if (*identifier == kGlFrontFacing)
1666 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001667 error(identifierLoc, "identifier should not be declared as invariant",
1668 identifier->c_str());
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001669 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001670 return nullptr;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001671 }
Jamie Madill2c433252014-12-03 12:36:54 -05001672 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001673 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
1674 ASSERT(variable);
1675 const TType &type = variable->getType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04001676 TIntermSymbol *intermSymbol =
1677 intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001678
1679 TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
1680 aggregate->setOp(EOpInvariantDeclaration);
1681 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001682 }
1683}
1684
Jamie Madillb98c3a82015-07-23 14:26:04 -04001685TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
1686 TIntermAggregate *aggregateDeclaration,
1687 const TSourceLoc &identifierLocation,
1688 const TString &identifier)
Jamie Madill502d66f2013-06-20 11:55:52 -04001689{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001690 // If the declaration starting this declarator list was empty (example: int,), some checks were
1691 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001692 if (mDeferredSingleDeclarationErrorCheck)
1693 {
1694 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1695 recover();
1696 mDeferredSingleDeclarationErrorCheck = false;
1697 }
1698
Jamie Madill0bd18df2013-06-20 11:55:52 -04001699 if (locationDeclaratorListCheck(identifierLocation, publicType))
1700 recover();
1701
Olli Etuaho376f1b52015-04-13 13:23:41 +03001702 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001703 recover();
1704
Olli Etuaho2935c582015-04-08 14:32:06 +03001705 TVariable *variable = nullptr;
1706 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001707 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001708
Jamie Madillb98c3a82015-07-23 14:26:04 -04001709 TIntermSymbol *symbol =
1710 intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001711 if (variable && symbol)
Jamie Madill502d66f2013-06-20 11:55:52 -04001712 symbol->setId(variable->getUniqueId());
1713
Olli Etuahoe7847b02015-03-16 11:56:12 +02001714 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001715}
1716
Jamie Madillb98c3a82015-07-23 14:26:04 -04001717TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
1718 TIntermAggregate *aggregateDeclaration,
1719 const TSourceLoc &identifierLocation,
1720 const TString &identifier,
1721 const TSourceLoc &arrayLocation,
1722 TIntermTyped *indexExpression)
Jamie Madill502d66f2013-06-20 11:55:52 -04001723{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001724 // If the declaration starting this declarator list was empty (example: int,), some checks were
1725 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001726 if (mDeferredSingleDeclarationErrorCheck)
1727 {
1728 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1729 recover();
1730 mDeferredSingleDeclarationErrorCheck = false;
1731 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001732
Jamie Madill0bd18df2013-06-20 11:55:52 -04001733 if (locationDeclaratorListCheck(identifierLocation, publicType))
1734 recover();
1735
Olli Etuaho376f1b52015-04-13 13:23:41 +03001736 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001737 recover();
1738
Jamie Madillb98c3a82015-07-23 14:26:04 -04001739 if (arrayTypeErrorCheck(arrayLocation, publicType) ||
1740 arrayQualifierErrorCheck(arrayLocation, publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001741 {
1742 recover();
1743 }
Olli Etuaho93a90fd2015-04-07 18:14:07 +03001744 else
Jamie Madill502d66f2013-06-20 11:55:52 -04001745 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001746 TType arrayType = TType(publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04001747 int size;
1748 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
Olli Etuahoe7847b02015-03-16 11:56:12 +02001749 {
Jamie Madill502d66f2013-06-20 11:55:52 -04001750 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001751 }
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001752 arrayType.setArraySize(size);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001753
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001754 TVariable *variable = nullptr;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001755 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001756 recover();
Jamie Madill502d66f2013-06-20 11:55:52 -04001757
Jamie Madillb98c3a82015-07-23 14:26:04 -04001758 TIntermSymbol *symbol =
1759 intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001760 if (variable && symbol)
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001761 symbol->setId(variable->getUniqueId());
Olli Etuahoe7847b02015-03-16 11:56:12 +02001762
1763 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001764 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001765
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001766 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001767}
1768
Jamie Madillb98c3a82015-07-23 14:26:04 -04001769TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
1770 TIntermAggregate *aggregateDeclaration,
1771 const TSourceLoc &identifierLocation,
1772 const TString &identifier,
1773 const TSourceLoc &initLocation,
1774 TIntermTyped *initializer)
Jamie Madill502d66f2013-06-20 11:55:52 -04001775{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001776 // If the declaration starting this declarator list was empty (example: int,), some checks were
1777 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001778 if (mDeferredSingleDeclarationErrorCheck)
1779 {
1780 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1781 recover();
1782 mDeferredSingleDeclarationErrorCheck = false;
1783 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001784
Jamie Madill0bd18df2013-06-20 11:55:52 -04001785 if (locationDeclaratorListCheck(identifierLocation, publicType))
1786 recover();
1787
Olli Etuahoe7847b02015-03-16 11:56:12 +02001788 TIntermNode *intermNode = nullptr;
1789 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill502d66f2013-06-20 11:55:52 -04001790 {
1791 //
1792 // build the intermediate representation
1793 //
1794 if (intermNode)
1795 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001796 return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001797 }
1798 else
1799 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001800 return aggregateDeclaration;
Jamie Madill502d66f2013-06-20 11:55:52 -04001801 }
1802 }
1803 else
1804 {
1805 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001806 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001807 }
1808}
1809
Jamie Madill06145232015-05-13 13:10:01 -04001810TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001811 TIntermAggregate *aggregateDeclaration,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301812 const TSourceLoc &identifierLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001813 const TString &identifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301814 const TSourceLoc &indexLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001815 TIntermTyped *indexExpression,
Jamie Madillb98c3a82015-07-23 14:26:04 -04001816 const TSourceLoc &initLocation,
1817 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001818{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001819 // If the declaration starting this declarator list was empty (example: int,), some checks were
1820 // not performed.
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001821 if (mDeferredSingleDeclarationErrorCheck)
1822 {
1823 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1824 recover();
1825 mDeferredSingleDeclarationErrorCheck = false;
1826 }
1827
1828 if (locationDeclaratorListCheck(identifierLocation, publicType))
1829 recover();
1830
Jamie Madillb98c3a82015-07-23 14:26:04 -04001831 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1832 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001833 {
1834 recover();
1835 }
1836
1837 TPublicType arrayType(publicType);
1838
Olli Etuaho376f1b52015-04-13 13:23:41 +03001839 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001840 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1841 // the initializer.
1842 if (indexExpression != nullptr &&
1843 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001844 {
1845 recover();
1846 }
1847 // Make the type an array even if size check failed.
1848 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1849 arrayType.setArraySize(size);
1850
1851 // initNode will correspond to the whole of "b[n] = initializer".
1852 TIntermNode *initNode = nullptr;
1853 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1854 {
1855 if (initNode)
1856 {
1857 return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
1858 }
1859 else
1860 {
1861 return aggregateDeclaration;
1862 }
1863 }
1864 else
1865 {
1866 recover();
1867 return nullptr;
1868 }
1869}
1870
Jamie Madilla295edf2013-06-06 11:56:48 -04001871void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1872{
1873 if (typeQualifier.qualifier != EvqUniform)
1874 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001875 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
1876 "global layout must be uniform");
Jamie Madilla295edf2013-06-06 11:56:48 -04001877 recover();
1878 return;
1879 }
1880
1881 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1882 ASSERT(!layoutQualifier.isEmpty());
1883
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001884 if (mShaderVersion < 300)
Jamie Madilla295edf2013-06-06 11:56:48 -04001885 {
1886 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1887 recover();
1888 return;
1889 }
1890
1891 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1892 {
1893 recover();
1894 return;
1895 }
1896
Jamie Madill099c0f32013-06-20 11:55:52 -04001897 if (layoutQualifier.matrixPacking != EmpUnspecified)
1898 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001899 mDefaultMatrixPacking = layoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04001900 }
1901
Geoff Langc6856732014-02-11 09:38:55 -05001902 if (layoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001903 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001904 mDefaultBlockStorage = layoutQualifier.blockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04001905 }
Jamie Madilla295edf2013-06-06 11:56:48 -04001906}
1907
Jamie Madill185fb402015-06-12 15:48:48 -04001908void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
1909 TFunction *function,
1910 TIntermAggregate **aggregateOut)
1911{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001912 const TSymbol *builtIn =
1913 symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04001914
1915 if (builtIn)
1916 {
1917 error(location, "built-in functions cannot be redefined", function->getName().c_str());
1918 recover();
1919 }
1920
Jamie Madillb98c3a82015-07-23 14:26:04 -04001921 TFunction *prevDec =
1922 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
Jamie Madill185fb402015-06-12 15:48:48 -04001923 //
1924 // Note: 'prevDec' could be 'function' if this is the first time we've seen function
1925 // as it would have just been put in the symbol table. Otherwise, we're looking up
1926 // an earlier occurance.
1927 //
1928 if (prevDec->isDefined())
1929 {
1930 // Then this function already has a body.
1931 error(location, "function already has a body", function->getName().c_str());
1932 recover();
1933 }
1934 prevDec->setDefined();
1935 //
1936 // Overload the unique ID of the definition to be the same unique ID as the declaration.
1937 // Eventually we will probably want to have only a single definition and just swap the
1938 // arguments to be the definition's arguments.
1939 //
1940 function->setUniqueId(prevDec->getUniqueId());
1941
1942 // Raise error message if main function takes any parameters or return anything other than void
1943 if (function->getName() == "main")
1944 {
1945 if (function->getParamCount() > 0)
1946 {
1947 error(location, "function cannot take any parameter(s)", function->getName().c_str());
1948 recover();
1949 }
1950 if (function->getReturnType().getBasicType() != EbtVoid)
1951 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001952 error(location, "", function->getReturnType().getBasicString(),
1953 "main function cannot return a value");
Jamie Madill185fb402015-06-12 15:48:48 -04001954 recover();
1955 }
1956 }
1957
1958 //
1959 // Remember the return type for later checking for RETURN statements.
1960 //
1961 setCurrentFunctionType(&(prevDec->getReturnType()));
1962 setFunctionReturnsValue(false);
1963
1964 //
1965 // Insert parameters into the symbol table.
1966 // If the parameter has no name, it's not an error, just don't insert it
1967 // (could be used for unused args).
1968 //
1969 // Also, accumulate the list of parameters into the HIL, so lower level code
1970 // knows where to find parameters.
1971 //
1972 TIntermAggregate *paramNodes = new TIntermAggregate;
1973 for (size_t i = 0; i < function->getParamCount(); i++)
1974 {
1975 const TConstParameter &param = function->getParam(i);
1976 if (param.name != 0)
1977 {
1978 TVariable *variable = new TVariable(param.name, *param.type);
1979 //
1980 // Insert the parameters with name in the symbol table.
1981 //
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001982 if (!symbolTable.declare(variable))
1983 {
Jamie Madill185fb402015-06-12 15:48:48 -04001984 error(location, "redefinition", variable->getName().c_str());
1985 recover();
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001986 paramNodes = intermediate.growAggregate(
1987 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
1988 continue;
Jamie Madill185fb402015-06-12 15:48:48 -04001989 }
1990
1991 //
1992 // Add the parameter to the HIL
1993 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04001994 TIntermSymbol *symbol = intermediate.addSymbol(
1995 variable->getUniqueId(), variable->getName(), variable->getType(), location);
Jamie Madill185fb402015-06-12 15:48:48 -04001996
1997 paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
1998 }
1999 else
2000 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002001 paramNodes = intermediate.growAggregate(
2002 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002003 }
2004 }
2005 intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
2006 *aggregateOut = paramNodes;
2007 setLoopNestingLevel(0);
2008}
2009
Jamie Madillb98c3a82015-07-23 14:26:04 -04002010TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
Jamie Madill185fb402015-06-12 15:48:48 -04002011{
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002012 //
2013 // Multiple declarations of the same function are allowed.
2014 //
2015 // If this is a definition, the definition production code will check for redefinitions
2016 // (we don't know at this point if it's a definition or not).
2017 //
2018 // Redeclarations are allowed. But, return types and parameter qualifiers must match.
2019 //
2020 TFunction *prevDec =
2021 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
2022 if (prevDec)
Jamie Madill185fb402015-06-12 15:48:48 -04002023 {
2024 if (prevDec->getReturnType() != function->getReturnType())
2025 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002026 error(location, "overloaded functions must have the same return type",
Jamie Madill185fb402015-06-12 15:48:48 -04002027 function->getReturnType().getBasicString());
2028 recover();
2029 }
2030 for (size_t i = 0; i < prevDec->getParamCount(); ++i)
2031 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002032 if (prevDec->getParam(i).type->getQualifier() !=
2033 function->getParam(i).type->getQualifier())
Jamie Madill185fb402015-06-12 15:48:48 -04002034 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002035 error(location, "overloaded functions must have the same parameter qualifiers",
Jamie Madill185fb402015-06-12 15:48:48 -04002036 function->getParam(i).type->getQualifierString());
2037 recover();
2038 }
2039 }
2040 }
2041
2042 //
2043 // Check for previously declared variables using the same name.
2044 //
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002045 TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002046 if (prevSym)
2047 {
2048 if (!prevSym->isFunction())
2049 {
2050 error(location, "redefinition", function->getName().c_str(), "function");
2051 recover();
2052 }
2053 }
2054 else
2055 {
2056 // Insert the unmangled name to detect potential future redefinition as a variable.
Jamie Madillb98c3a82015-07-23 14:26:04 -04002057 TFunction *newFunction =
2058 new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
Jamie Madill185fb402015-06-12 15:48:48 -04002059 symbolTable.getOuterLevel()->insertUnmangled(newFunction);
2060 }
2061
2062 // We're at the inner scope level of the function's arguments and body statement.
2063 // Add the function prototype to the surrounding scope instead.
2064 symbolTable.getOuterLevel()->insert(function);
2065
2066 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002067 // If this is a redeclaration, it could also be a definition, in which case, we want to use the
2068 // variable names from this one, and not the one that's
Jamie Madill185fb402015-06-12 15:48:48 -04002069 // being redeclared. So, pass back up this declaration, not the one in the symbol table.
2070 //
2071 return function;
2072}
2073
Jamie Madill06145232015-05-13 13:10:01 -04002074TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002075{
Jamie Madill06145232015-05-13 13:10:01 -04002076 TPublicType publicType = publicTypeIn;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002077 TOperator op = EOpNull;
2078 if (publicType.userDef)
2079 {
2080 op = EOpConstructStruct;
2081 }
2082 else
2083 {
2084 switch (publicType.type)
2085 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002086 case EbtFloat:
2087 if (publicType.isMatrix())
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002088 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002089 switch (publicType.getCols())
Alexis Hetu07e57df2015-06-16 16:55:52 -04002090 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002091 case 2:
2092 switch (publicType.getRows())
2093 {
2094 case 2:
2095 op = EOpConstructMat2;
2096 break;
2097 case 3:
2098 op = EOpConstructMat2x3;
2099 break;
2100 case 4:
2101 op = EOpConstructMat2x4;
2102 break;
2103 }
2104 break;
2105 case 3:
2106 switch (publicType.getRows())
2107 {
2108 case 2:
2109 op = EOpConstructMat3x2;
2110 break;
2111 case 3:
2112 op = EOpConstructMat3;
2113 break;
2114 case 4:
2115 op = EOpConstructMat3x4;
2116 break;
2117 }
2118 break;
2119 case 4:
2120 switch (publicType.getRows())
2121 {
2122 case 2:
2123 op = EOpConstructMat4x2;
2124 break;
2125 case 3:
2126 op = EOpConstructMat4x3;
2127 break;
2128 case 4:
2129 op = EOpConstructMat4;
2130 break;
2131 }
2132 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -04002133 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002134 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002135 else
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002136 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002137 switch (publicType.getNominalSize())
2138 {
2139 case 1:
2140 op = EOpConstructFloat;
2141 break;
2142 case 2:
2143 op = EOpConstructVec2;
2144 break;
2145 case 3:
2146 op = EOpConstructVec3;
2147 break;
2148 case 4:
2149 op = EOpConstructVec4;
2150 break;
2151 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002152 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002153 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002154
Jamie Madillb98c3a82015-07-23 14:26:04 -04002155 case EbtInt:
2156 switch (publicType.getNominalSize())
2157 {
2158 case 1:
2159 op = EOpConstructInt;
2160 break;
2161 case 2:
2162 op = EOpConstructIVec2;
2163 break;
2164 case 3:
2165 op = EOpConstructIVec3;
2166 break;
2167 case 4:
2168 op = EOpConstructIVec4;
2169 break;
2170 }
2171 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002172
Jamie Madillb98c3a82015-07-23 14:26:04 -04002173 case EbtUInt:
2174 switch (publicType.getNominalSize())
2175 {
2176 case 1:
2177 op = EOpConstructUInt;
2178 break;
2179 case 2:
2180 op = EOpConstructUVec2;
2181 break;
2182 case 3:
2183 op = EOpConstructUVec3;
2184 break;
2185 case 4:
2186 op = EOpConstructUVec4;
2187 break;
2188 }
2189 break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002190
Jamie Madillb98c3a82015-07-23 14:26:04 -04002191 case EbtBool:
2192 switch (publicType.getNominalSize())
2193 {
2194 case 1:
2195 op = EOpConstructBool;
2196 break;
2197 case 2:
2198 op = EOpConstructBVec2;
2199 break;
2200 case 3:
2201 op = EOpConstructBVec3;
2202 break;
2203 case 4:
2204 op = EOpConstructBVec4;
2205 break;
2206 }
2207 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002208
Jamie Madillb98c3a82015-07-23 14:26:04 -04002209 default:
2210 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002211 }
2212
2213 if (op == EOpNull)
2214 {
2215 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
2216 recover();
2217 publicType.type = EbtFloat;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002218 op = EOpConstructFloat;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002219 }
2220 }
2221
2222 TString tempString;
Dmitry Skiba7f17a502015-06-22 15:08:39 -07002223 const TType *type = new TType(publicType);
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002224 return new TFunction(&tempString, type, op);
2225}
2226
Jamie Madillb98c3a82015-07-23 14:26:04 -04002227// This function is used to test for the correctness of the parameters passed to various constructor
2228// functions and also convert them to the right datatype if it is allowed and required.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002229//
2230// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
2231//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002232TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
2233 TType *type,
2234 TOperator op,
2235 TFunction *fnCall,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302236 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002237{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002238 TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002239
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002240 if (!aggregateArguments)
2241 {
2242 aggregateArguments = new TIntermAggregate;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002243 aggregateArguments->getSequence()->push_back(arguments);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002244 }
2245
Olli Etuahof40319e2015-03-10 14:33:00 +02002246 if (type->isArray())
2247 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002248 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
2249 // the array.
Olli Etuahof40319e2015-03-10 14:33:00 +02002250 TIntermSequence *args = aggregateArguments->getSequence();
2251 for (size_t i = 0; i < args->size(); i++)
2252 {
2253 const TType &argType = (*args)[i]->getAsTyped()->getType();
2254 // It has already been checked that the argument is not an array.
2255 ASSERT(!argType.isArray());
2256 if (!argType.sameElementType(*type))
2257 {
2258 error(line, "Array constructor argument has an incorrect type", "Error");
2259 recover();
2260 return nullptr;
2261 }
2262 }
2263 }
2264 else if (op == EOpConstructStruct)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002265 {
2266 const TFieldList &fields = type->getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002267 TIntermSequence *args = aggregateArguments->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002268
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002269 for (size_t i = 0; i < fields.size(); i++)
2270 {
Nicolas Capensffd73872014-08-21 13:49:16 -04002271 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002272 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002273 error(line, "Structure constructor arguments do not match structure fields",
2274 "Error");
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002275 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002276
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002277 return 0;
2278 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002279 }
2280 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002281
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002282 // Turn the argument list itself into a constructor
Jamie Madillb98c3a82015-07-23 14:26:04 -04002283 TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
Olli Etuaho21203702014-11-13 16:16:21 +02002284 TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002285 if (constConstructor)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002286 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002287 return constConstructor;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002288 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002289
Olli Etuaho21203702014-11-13 16:16:21 +02002290 // Structs should not be precision qualified, the individual members may be.
2291 // Built-in types on the other hand should be precision qualified.
2292 if (op != EOpConstructStruct)
2293 {
2294 constructor->setPrecisionFromChildren();
2295 type->setPrecision(constructor->getPrecision());
2296 }
2297
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002298 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002299}
2300
Arun Patole7e7e68d2015-05-22 12:02:25 +05302301TIntermTyped *TParseContext::foldConstConstructor(TIntermAggregate *aggrNode, const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002302{
Olli Etuahof40319e2015-03-10 14:33:00 +02002303 // TODO: Add support for folding array constructors
2304 bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002305 aggrNode->setType(type);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302306 if (canBeFolded)
2307 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002308 bool returnVal = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302309 TConstantUnion *unionArray = new TConstantUnion[type.getObjectSize()];
2310 if (aggrNode->getSequence()->size() == 1)
2311 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002312 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2313 aggrNode->getOp(), type, true);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002314 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302315 else
2316 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002317 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2318 aggrNode->getOp(), type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002319 }
2320 if (returnVal)
2321 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002322
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002323 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
2324 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002325
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002326 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002327}
2328
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002329//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002330// This function returns the tree representation for the vector field(s) being accessed from contant
2331// vector.
2332// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a
2333// contant node is returned, else an aggregate node is returned (for v.xy). The input to this
2334// function could either
2335// be the symbol node or it could be the intermediate tree representation of accessing fields in a
2336// constant
2337// structure or column of a constant matrix.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002338//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002339TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields,
2340 TIntermTyped *node,
2341 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002342{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302343 TIntermTyped *typedNode;
2344 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002345
Jamie Madillb11e2482015-05-04 14:21:22 -04002346 const TConstantUnion *unionArray;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302347 if (tempConstantNode)
2348 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002349 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002350
Arun Patole7e7e68d2015-05-22 12:02:25 +05302351 if (!unionArray)
2352 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002353 return node;
2354 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302355 }
2356 else
Jamie Madillb98c3a82015-07-23 14:26:04 -04002357 { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else,
2358 // its an error
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002359 error(line, "Cannot offset into the vector", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002360 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002361
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002362 return 0;
2363 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002364
Arun Patole7e7e68d2015-05-22 12:02:25 +05302365 TConstantUnion *constArray = new TConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002366
Arun Patole7e7e68d2015-05-22 12:02:25 +05302367 for (int i = 0; i < fields.num; i++)
2368 {
2369 if (fields.offsets[i] >= node->getType().getNominalSize())
2370 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002371 std::stringstream extraInfoStream;
2372 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
2373 std::string extraInfo = extraInfoStream.str();
2374 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002375 recover();
2376 fields.offsets[i] = 0;
2377 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302378
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002379 constArray[i] = unionArray[fields.offsets[i]];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302380 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002381 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
2382 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002383}
2384
2385//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002386// This function returns the column being accessed from a constant matrix. The values are retrieved
2387// from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector).
2388// The
2389// input to the function could either be a symbol node (m[0] where m is a constant matrix)that
2390// represents
2391// a constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s
2392// is a constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002393//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002394TIntermTyped *TParseContext::addConstMatrixNode(int index,
2395 TIntermTyped *node,
2396 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002397{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302398 TIntermTyped *typedNode;
2399 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002400
Arun Patole7e7e68d2015-05-22 12:02:25 +05302401 if (index >= node->getType().getCols())
2402 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002403 std::stringstream extraInfoStream;
2404 extraInfoStream << "matrix field selection out of range '" << index << "'";
2405 std::string extraInfo = extraInfoStream.str();
2406 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002407 recover();
2408 index = 0;
2409 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002410
Arun Patole7e7e68d2015-05-22 12:02:25 +05302411 if (tempConstantNode)
2412 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002413 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
2414 int size = tempConstantNode->getType().getCols();
2415 typedNode = intermediate.addConstantUnion(&unionArray[size * index],
2416 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302417 }
2418 else
2419 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002420 error(line, "Cannot offset into the matrix", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002421 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002422
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002423 return 0;
2424 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002425
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002426 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002427}
2428
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002429//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002430// This function returns an element of an array accessed from a constant array. The values are
2431// retrieved from the symbol table and parse-tree is built for the type of the element. The input
Arun Patole7e7e68d2015-05-22 12:02:25 +05302432// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
Jamie Madillb98c3a82015-07-23 14:26:04 -04002433// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a
2434// constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002435//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002436TIntermTyped *TParseContext::addConstArrayNode(int index,
2437 TIntermTyped *node,
2438 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002439{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302440 TIntermTyped *typedNode;
2441 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002442 TType arrayElementType = node->getType();
2443 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002444
Arun Patole7e7e68d2015-05-22 12:02:25 +05302445 if (index >= node->getType().getArraySize())
2446 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002447 std::stringstream extraInfoStream;
2448 extraInfoStream << "array field selection out of range '" << index << "'";
2449 std::string extraInfo = extraInfoStream.str();
2450 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002451 recover();
2452 index = 0;
2453 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002454
Arun Patole7e7e68d2015-05-22 12:02:25 +05302455 if (tempConstantNode)
2456 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002457 size_t arrayElementSize = arrayElementType.getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302458 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002459 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index],
2460 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302461 }
2462 else
2463 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002464 error(line, "Cannot offset into the array", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002465 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002466
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002467 return 0;
2468 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002469
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002470 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002471}
2472
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002473//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002474// This function returns the value of a particular field inside a constant structure from the symbol
2475// table.
2476// If there is an embedded/nested struct, it appropriately calls addConstStructNested or
2477// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
2478// struct.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002479//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002480TIntermTyped *TParseContext::addConstStruct(const TString &identifier,
2481 TIntermTyped *node,
2482 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002483{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302484 const TFieldList &fields = node->getType().getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002485 size_t instanceSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002486
Arun Patole7e7e68d2015-05-22 12:02:25 +05302487 for (size_t index = 0; index < fields.size(); ++index)
2488 {
2489 if (fields[index]->name() == identifier)
2490 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002491 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302492 }
2493 else
2494 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002495 instanceSize += fields[index]->type()->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002496 }
2497 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002498
Jamie Madill94bf7f22013-07-08 13:31:15 -04002499 TIntermTyped *typedNode;
2500 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302501 if (tempConstantNode)
2502 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002503 TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002504
Jamie Madillb98c3a82015-07-23 14:26:04 -04002505 // type will be changed in the calling function
2506 typedNode = intermediate.addConstantUnion(constArray + instanceSize,
2507 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302508 }
2509 else
2510 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002511 error(line, "Cannot offset into the structure", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002512 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002513
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002514 return 0;
2515 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002516
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002517 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002518}
2519
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002520//
2521// Interface/uniform blocks
2522//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002523TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualifier,
2524 const TSourceLoc &nameLine,
2525 const TString &blockName,
2526 TFieldList *fieldList,
2527 const TString *instanceName,
2528 const TSourceLoc &instanceLine,
2529 TIntermTyped *arrayIndex,
2530 const TSourceLoc &arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002531{
2532 if (reservedErrorCheck(nameLine, blockName))
2533 recover();
2534
2535 if (typeQualifier.qualifier != EvqUniform)
2536 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302537 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
2538 "interface blocks must be uniform");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002539 recover();
2540 }
2541
Jamie Madill099c0f32013-06-20 11:55:52 -04002542 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
2543 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002544 {
2545 recover();
2546 }
2547
Jamie Madill099c0f32013-06-20 11:55:52 -04002548 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
2549 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002550 blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002551 }
2552
Jamie Madill1566ef72013-06-20 11:55:54 -04002553 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
2554 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002555 blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04002556 }
2557
Arun Patole7e7e68d2015-05-22 12:02:25 +05302558 TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
2559 if (!symbolTable.declare(blockNameSymbol))
2560 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002561 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
2562 recover();
2563 }
2564
Jamie Madill98493dd2013-07-08 14:39:03 -04002565 // check for sampler types and apply layout qualifiers
Arun Patole7e7e68d2015-05-22 12:02:25 +05302566 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2567 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002568 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302569 TType *fieldType = field->type();
2570 if (IsSampler(fieldType->getBasicType()))
2571 {
2572 error(field->line(), "unsupported type", fieldType->getBasicString(),
2573 "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002574 recover();
2575 }
2576
Jamie Madill98493dd2013-07-08 14:39:03 -04002577 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002578 switch (qualifier)
2579 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002580 case EvqGlobal:
2581 case EvqUniform:
2582 break;
2583 default:
2584 error(field->line(), "invalid qualifier on interface block member",
2585 getQualifierString(qualifier));
2586 recover();
2587 break;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002588 }
Jamie Madilla5efff92013-06-06 11:56:47 -04002589
2590 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04002591 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
2592 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002593 {
2594 recover();
2595 }
Jamie Madill099c0f32013-06-20 11:55:52 -04002596
Jamie Madill98493dd2013-07-08 14:39:03 -04002597 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04002598 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002599 error(field->line(), "invalid layout qualifier:",
2600 getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04002601 recover();
2602 }
2603
Jamie Madill98493dd2013-07-08 14:39:03 -04002604 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04002605 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002606 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002607 }
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002608 else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
Jamie Madill099c0f32013-06-20 11:55:52 -04002609 {
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002610 warning(field->line(), "extraneous layout qualifier:",
Jamie Madillb98c3a82015-07-23 14:26:04 -04002611 getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
2612 "only has an effect on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04002613 }
2614
Jamie Madill98493dd2013-07-08 14:39:03 -04002615 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002616 }
2617
Jamie Madill98493dd2013-07-08 14:39:03 -04002618 // add array index
2619 int arraySize = 0;
2620 if (arrayIndex != NULL)
2621 {
2622 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
2623 recover();
2624 }
2625
Jamie Madillb98c3a82015-07-23 14:26:04 -04002626 TInterfaceBlock *interfaceBlock =
2627 new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
2628 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
2629 arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002630
2631 TString symbolName = "";
Jamie Madillb98c3a82015-07-23 14:26:04 -04002632 int symbolId = 0;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002633
Jamie Madill98493dd2013-07-08 14:39:03 -04002634 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002635 {
2636 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04002637 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2638 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002639 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302640 TType *fieldType = field->type();
Jamie Madill98493dd2013-07-08 14:39:03 -04002641
2642 // set parent pointer of the field variable
2643 fieldType->setInterfaceBlock(interfaceBlock);
2644
Arun Patole7e7e68d2015-05-22 12:02:25 +05302645 TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -04002646 fieldVariable->setQualifier(typeQualifier.qualifier);
2647
Arun Patole7e7e68d2015-05-22 12:02:25 +05302648 if (!symbolTable.declare(fieldVariable))
2649 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002650 error(field->line(), "redefinition", field->name().c_str(),
2651 "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002652 recover();
2653 }
2654 }
2655 }
2656 else
2657 {
Olli Etuahoe0f623a2015-07-10 11:58:30 +03002658 if (reservedErrorCheck(instanceLine, *instanceName))
2659 recover();
2660
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002661 // add a symbol for this interface block
Arun Patole7e7e68d2015-05-22 12:02:25 +05302662 TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002663 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04002664
Arun Patole7e7e68d2015-05-22 12:02:25 +05302665 if (!symbolTable.declare(instanceTypeDef))
2666 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002667 error(instanceLine, "redefinition", instanceName->c_str(),
2668 "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002669 recover();
2670 }
2671
Jamie Madillb98c3a82015-07-23 14:26:04 -04002672 symbolId = instanceTypeDef->getUniqueId();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002673 symbolName = instanceTypeDef->getName();
2674 }
2675
Jamie Madillb98c3a82015-07-23 14:26:04 -04002676 TIntermAggregate *aggregate = intermediate.makeAggregate(
2677 intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
2678 nameLine);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002679 aggregate->setOp(EOpDeclaration);
Jamie Madill98493dd2013-07-08 14:39:03 -04002680
2681 exitStructDeclaration();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002682 return aggregate;
2683}
2684
Arun Patole7e7e68d2015-05-22 12:02:25 +05302685bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002686{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002687 ++mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002688
2689 // Embedded structure definitions are not supported per GLSL ES spec.
2690 // They aren't allowed in GLSL either, but we need to detect this here
2691 // so we don't rely on the GLSL compiler to catch it.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302692 if (mStructNestingLevel > 1)
2693 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002694 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002695 return true;
2696 }
2697
2698 return false;
2699}
2700
2701void TParseContext::exitStructDeclaration()
2702{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002703 --mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002704}
2705
Jamie Madillb98c3a82015-07-23 14:26:04 -04002706namespace
2707{
kbr@chromium.org476541f2011-10-27 21:14:51 +00002708const int kWebGLMaxStructNesting = 4;
2709
2710} // namespace
2711
Arun Patole7e7e68d2015-05-22 12:02:25 +05302712bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002713{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302714 if (!IsWebGLBasedSpec(mShaderSpec))
2715 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002716 return false;
2717 }
2718
Arun Patole7e7e68d2015-05-22 12:02:25 +05302719 if (field.type()->getBasicType() != EbtStruct)
2720 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002721 return false;
2722 }
2723
2724 // We're already inside a structure definition at this point, so add
2725 // one to the field's struct nesting.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302726 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
2727 {
Jamie Madill41a49272014-03-18 16:10:13 -04002728 std::stringstream reasonStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002729 reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
2730 << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
Jamie Madill41a49272014-03-18 16:10:13 -04002731 std::string reason = reasonStream.str();
2732 error(line, reason.c_str(), field.name().c_str(), "");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002733 return true;
2734 }
2735
2736 return false;
2737}
2738
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00002739//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002740// Parse an array index expression
2741//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002742TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
2743 const TSourceLoc &location,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302744 TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002745{
2746 TIntermTyped *indexedExpression = NULL;
2747
2748 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2749 {
2750 if (baseExpression->getAsSymbolNode())
2751 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302752 error(location, " left of '[' is not of type array, matrix, or vector ",
2753 baseExpression->getAsSymbolNode()->getSymbol().c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002754 }
2755 else
2756 {
2757 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2758 }
2759 recover();
2760 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002761
Jamie Madill21c1e452014-12-29 11:33:41 -05002762 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2763
2764 if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04002765 {
Jamie Madill21c1e452014-12-29 11:33:41 -05002766 int index = indexConstantUnion->getIConst(0);
Jamie Madill7164cf42013-07-08 13:30:59 -04002767 if (index < 0)
2768 {
2769 std::stringstream infoStream;
2770 infoStream << index;
2771 std::string info = infoStream.str();
2772 error(location, "negative index", info.c_str());
2773 recover();
2774 index = 0;
2775 }
2776 if (baseExpression->getType().getQualifier() == EvqConst)
2777 {
2778 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002779 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002780 // constant folding for arrays
2781 indexedExpression = addConstArrayNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002782 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002783 else if (baseExpression->isVector())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002784 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002785 // constant folding for vectors
2786 TVectorFields fields;
2787 fields.num = 1;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002788 fields.offsets[0] =
2789 index; // need to do it this way because v.xy sends fields integer array
Jamie Madill7164cf42013-07-08 13:30:59 -04002790 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2791 }
2792 else if (baseExpression->isMatrix())
2793 {
2794 // constant folding for matrices
2795 indexedExpression = addConstMatrixNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002796 }
2797 }
2798 else
2799 {
Jamie Madillb11e2482015-05-04 14:21:22 -04002800 int safeIndex = -1;
2801
Jamie Madill7164cf42013-07-08 13:30:59 -04002802 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002803 {
Jamie Madill18464b52013-07-08 14:01:55 -04002804 if (index >= baseExpression->getType().getArraySize())
Jamie Madill7164cf42013-07-08 13:30:59 -04002805 {
2806 std::stringstream extraInfoStream;
2807 extraInfoStream << "array index out of range '" << index << "'";
2808 std::string extraInfo = extraInfoStream.str();
2809 error(location, "", "[", extraInfo.c_str());
2810 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002811 safeIndex = baseExpression->getType().getArraySize() - 1;
Jamie Madill7164cf42013-07-08 13:30:59 -04002812 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302813 else if (baseExpression->getQualifier() == EvqFragData && index > 0 &&
2814 !isExtensionEnabled("GL_EXT_draw_buffers"))
Jamie Madill5d287f52013-07-12 15:38:19 -04002815 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002816 error(location, "", "[",
2817 "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is "
2818 "disabled");
Jamie Madill5d287f52013-07-12 15:38:19 -04002819 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002820 safeIndex = 0;
Jamie Madill5d287f52013-07-12 15:38:19 -04002821 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002822 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302823 else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
Jamie Madillb98c3a82015-07-23 14:26:04 -04002824 baseExpression->getType().getNominalSize() <= index)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002825 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002826 std::stringstream extraInfoStream;
2827 extraInfoStream << "field selection out of range '" << index << "'";
2828 std::string extraInfo = extraInfoStream.str();
2829 error(location, "", "[", extraInfo.c_str());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002830 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002831 safeIndex = baseExpression->getType().getNominalSize() - 1;
Jamie Madill46131a32013-06-20 11:55:50 -04002832 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002833
Jamie Madillb11e2482015-05-04 14:21:22 -04002834 // Don't modify the data of the previous constant union, because it can point
2835 // to builtins, like gl_MaxDrawBuffers. Instead use a new sanitized object.
2836 if (safeIndex != -1)
2837 {
2838 TConstantUnion *safeConstantUnion = new TConstantUnion();
2839 safeConstantUnion->setIConst(safeIndex);
2840 indexConstantUnion->replaceConstantUnion(safeConstantUnion);
2841 }
2842
Jamie Madillb98c3a82015-07-23 14:26:04 -04002843 indexedExpression =
2844 intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002845 }
2846 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002847 else
2848 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002849 if (baseExpression->isInterfaceBlock())
Jamie Madill7164cf42013-07-08 13:30:59 -04002850 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002851 error(
2852 location, "", "[",
2853 "array indexes for interface blocks arrays must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002854 recover();
2855 }
Jamie Madill19571812013-08-12 15:26:34 -07002856 else if (baseExpression->getQualifier() == EvqFragmentOut)
Jamie Madill7164cf42013-07-08 13:30:59 -04002857 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002858 error(location, "", "[",
2859 "array indexes for fragment outputs must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002860 recover();
2861 }
2862
Jamie Madillb98c3a82015-07-23 14:26:04 -04002863 indexedExpression =
2864 intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
Jamie Madill7164cf42013-07-08 13:30:59 -04002865 }
2866
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002867 if (indexedExpression == 0)
2868 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04002869 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002870 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002871 indexedExpression =
2872 intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002873 }
2874 else if (baseExpression->isArray())
2875 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002876 const TType &baseType = baseExpression->getType();
2877 if (baseType.getStruct())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002878 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002879 TType copyOfType(baseType.getStruct());
2880 indexedExpression->setType(copyOfType);
2881 }
2882 else if (baseType.isInterfaceBlock())
2883 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002884 TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(),
2885 baseType.getLayoutQualifier(), 0);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002886 indexedExpression->setType(copyOfType);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002887 }
2888 else
2889 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002890 indexedExpression->setType(
2891 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary,
2892 static_cast<unsigned char>(baseExpression->getNominalSize()),
2893 static_cast<unsigned char>(baseExpression->getSecondarySize())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002894 }
2895
2896 if (baseExpression->getType().getQualifier() == EvqConst)
2897 {
2898 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2899 }
2900 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002901 else if (baseExpression->isMatrix())
2902 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002903 TQualifier qualifier =
2904 baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2905 indexedExpression->setType(TType(baseExpression->getBasicType(),
2906 baseExpression->getPrecision(), qualifier,
2907 static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002908 }
2909 else if (baseExpression->isVector())
2910 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002911 TQualifier qualifier =
2912 baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2913 indexedExpression->setType(
2914 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002915 }
2916 else
2917 {
2918 indexedExpression->setType(baseExpression->getType());
2919 }
2920
2921 return indexedExpression;
2922}
2923
Jamie Madillb98c3a82015-07-23 14:26:04 -04002924TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
2925 const TSourceLoc &dotLocation,
2926 const TString &fieldString,
2927 const TSourceLoc &fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002928{
2929 TIntermTyped *indexedExpression = NULL;
2930
2931 if (baseExpression->isArray())
2932 {
2933 error(fieldLocation, "cannot apply dot operator to an array", ".");
2934 recover();
2935 }
2936
2937 if (baseExpression->isVector())
2938 {
2939 TVectorFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002940 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
2941 fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002942 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002943 fields.num = 1;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002944 fields.offsets[0] = 0;
2945 recover();
2946 }
2947
2948 if (baseExpression->getType().getQualifier() == EvqConst)
2949 {
2950 // constant folding for vector fields
2951 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2952 if (indexedExpression == 0)
2953 {
2954 recover();
2955 indexedExpression = baseExpression;
2956 }
2957 else
2958 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002959 indexedExpression->setType(TType(baseExpression->getBasicType(),
2960 baseExpression->getPrecision(), EvqConst,
2961 (unsigned char)(fieldString).size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002962 }
2963 }
2964 else
2965 {
2966 TString vectorString = fieldString;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302967 TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002968 indexedExpression =
2969 intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
2970 indexedExpression->setType(TType(baseExpression->getBasicType(),
2971 baseExpression->getPrecision(), EvqTemporary,
2972 (unsigned char)vectorString.size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002973 }
2974 }
2975 else if (baseExpression->isMatrix())
2976 {
2977 TMatrixFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002978 if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(),
2979 fields, fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002980 {
2981 fields.wholeRow = false;
2982 fields.wholeCol = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002983 fields.row = 0;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002984 fields.col = 0;
2985 recover();
2986 }
2987
2988 if (fields.wholeRow || fields.wholeCol)
2989 {
2990 error(dotLocation, " non-scalar fields not implemented yet", ".");
2991 recover();
Jamie Madill6ba6ead2015-05-04 14:21:21 -04002992 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002993 unionArray->setIConst(0);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002994 TIntermTyped *index = intermediate.addConstantUnion(
2995 unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2996 indexedExpression =
2997 intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
2998 indexedExpression->setType(
2999 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary,
3000 static_cast<unsigned char>(baseExpression->getCols()),
3001 static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003002 }
3003 else
3004 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003005 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003006 unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003007 TIntermTyped *index = intermediate.addConstantUnion(
3008 unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
3009 indexedExpression =
3010 intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
3011 indexedExpression->setType(
3012 TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003013 }
3014 }
3015 else if (baseExpression->getBasicType() == EbtStruct)
3016 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003017 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05303018 const TFieldList &fields = baseExpression->getType().getStruct()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003019 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003020 {
3021 error(dotLocation, "structure has no fields", "Internal Error");
3022 recover();
3023 indexedExpression = baseExpression;
3024 }
3025 else
3026 {
3027 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003028 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003029 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003030 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003031 {
3032 fieldFound = true;
3033 break;
3034 }
3035 }
3036 if (fieldFound)
3037 {
3038 if (baseExpression->getType().getQualifier() == EvqConst)
3039 {
3040 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
3041 if (indexedExpression == 0)
3042 {
3043 recover();
3044 indexedExpression = baseExpression;
3045 }
3046 else
3047 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003048 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003049 // change the qualifier of the return type, not of the structure field
3050 // as the structure definition is shared between various structures.
3051 indexedExpression->getTypePointer()->setQualifier(EvqConst);
3052 }
3053 }
3054 else
3055 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003056 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003057 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003058 TIntermTyped *index = intermediate.addConstantUnion(
3059 unionArray, *fields[i]->type(), fieldLocation);
3060 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression,
3061 index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003062 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003063 }
3064 }
3065 else
3066 {
3067 error(dotLocation, " no such field in structure", fieldString.c_str());
3068 recover();
3069 indexedExpression = baseExpression;
3070 }
3071 }
3072 }
Jamie Madill98493dd2013-07-08 14:39:03 -04003073 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003074 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003075 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05303076 const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003077 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003078 {
3079 error(dotLocation, "interface block has no fields", "Internal Error");
3080 recover();
3081 indexedExpression = baseExpression;
3082 }
3083 else
3084 {
3085 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003086 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003087 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003088 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003089 {
3090 fieldFound = true;
3091 break;
3092 }
3093 }
3094 if (fieldFound)
3095 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003096 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003097 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003098 TIntermTyped *index =
3099 intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
3100 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock,
3101 baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003102 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003103 }
3104 else
3105 {
3106 error(dotLocation, " no such field in interface block", fieldString.c_str());
3107 recover();
3108 indexedExpression = baseExpression;
3109 }
3110 }
3111 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003112 else
3113 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003114 if (mShaderVersion < 300)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003115 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003116 error(dotLocation,
3117 " field selection requires structure, vector, or matrix on left hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303118 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003119 }
3120 else
3121 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303122 error(dotLocation,
Jamie Madillb98c3a82015-07-23 14:26:04 -04003123 " field selection requires structure, vector, matrix, or interface block on left "
3124 "hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303125 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003126 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003127 recover();
3128 indexedExpression = baseExpression;
3129 }
3130
3131 return indexedExpression;
3132}
3133
Jamie Madillb98c3a82015-07-23 14:26:04 -04003134TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3135 const TSourceLoc &qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003136{
Jamie Madilla5efff92013-06-06 11:56:47 -04003137 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003138
Jamie Madillb98c3a82015-07-23 14:26:04 -04003139 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003140 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003141 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003142
3143 if (qualifierType == "shared")
3144 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003145 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003146 }
3147 else if (qualifierType == "packed")
3148 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003149 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003150 }
3151 else if (qualifierType == "std140")
3152 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003153 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003154 }
3155 else if (qualifierType == "row_major")
3156 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003157 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003158 }
3159 else if (qualifierType == "column_major")
3160 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003161 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003162 }
3163 else if (qualifierType == "location")
3164 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003165 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3166 "location requires an argument");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003167 recover();
3168 }
3169 else
3170 {
3171 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
3172 recover();
3173 }
3174
Jamie Madilla5efff92013-06-06 11:56:47 -04003175 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003176}
3177
Jamie Madillb98c3a82015-07-23 14:26:04 -04003178TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3179 const TSourceLoc &qualifierTypeLine,
3180 const TString &intValueString,
3181 int intValue,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303182 const TSourceLoc &intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003183{
Jamie Madilla5efff92013-06-06 11:56:47 -04003184 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003185
Jamie Madillb98c3a82015-07-23 14:26:04 -04003186 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003187 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003188 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003189
3190 if (qualifierType != "location")
3191 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303192 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3193 "only location may have arguments");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003194 recover();
3195 }
3196 else
3197 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04003198 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003199 if (intValue < 0)
3200 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003201 error(intValueLine, "out of range:", intValueString.c_str(),
3202 "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003203 recover();
3204 }
3205 else
3206 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003207 qualifier.location = intValue;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003208 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003209 }
3210
Jamie Madilla5efff92013-06-06 11:56:47 -04003211 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003212}
3213
Jamie Madillb98c3a82015-07-23 14:26:04 -04003214TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
3215 TLayoutQualifier rightQualifier)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003216{
Jamie Madilla5efff92013-06-06 11:56:47 -04003217 TLayoutQualifier joinedQualifier = leftQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003218
Jamie Madilla5efff92013-06-06 11:56:47 -04003219 if (rightQualifier.location != -1)
3220 {
3221 joinedQualifier.location = rightQualifier.location;
3222 }
3223 if (rightQualifier.matrixPacking != EmpUnspecified)
3224 {
3225 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
3226 }
3227 if (rightQualifier.blockStorage != EbsUnspecified)
3228 {
3229 joinedQualifier.blockStorage = rightQualifier.blockStorage;
3230 }
3231
3232 return joinedQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003233}
3234
Arun Patole7e7e68d2015-05-22 12:02:25 +05303235TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
3236 TQualifier interpolationQualifier,
3237 const TSourceLoc &storageLoc,
3238 TQualifier storageQualifier)
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003239{
3240 TQualifier mergedQualifier = EvqSmoothIn;
3241
Arun Patole7e7e68d2015-05-22 12:02:25 +05303242 if (storageQualifier == EvqFragmentIn)
3243 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003244 if (interpolationQualifier == EvqSmooth)
3245 mergedQualifier = EvqSmoothIn;
3246 else if (interpolationQualifier == EvqFlat)
3247 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003248 else
3249 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003250 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303251 else if (storageQualifier == EvqCentroidIn)
3252 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003253 if (interpolationQualifier == EvqSmooth)
3254 mergedQualifier = EvqCentroidIn;
3255 else if (interpolationQualifier == EvqFlat)
3256 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003257 else
3258 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003259 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303260 else if (storageQualifier == EvqVertexOut)
3261 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003262 if (interpolationQualifier == EvqSmooth)
3263 mergedQualifier = EvqSmoothOut;
3264 else if (interpolationQualifier == EvqFlat)
3265 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003266 else
3267 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003268 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303269 else if (storageQualifier == EvqCentroidOut)
3270 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003271 if (interpolationQualifier == EvqSmooth)
3272 mergedQualifier = EvqCentroidOut;
3273 else if (interpolationQualifier == EvqFlat)
3274 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003275 else
3276 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003277 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303278 else
3279 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003280 error(interpolationLoc,
3281 "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303282 getInterpolationString(interpolationQualifier));
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003283 recover();
3284
3285 mergedQualifier = storageQualifier;
3286 }
3287
3288 TPublicType type;
3289 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
3290 return type;
3291}
3292
Jamie Madillb98c3a82015-07-23 14:26:04 -04003293TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
3294 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003295{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03003296 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
3297 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003298 recover();
3299 }
3300
Arun Patole7e7e68d2015-05-22 12:02:25 +05303301 for (unsigned int i = 0; i < fieldList->size(); ++i)
3302 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003303 //
3304 // Careful not to replace already known aspects of type, like array-ness
3305 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303306 TType *type = (*fieldList)[i]->type();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003307 type->setBasicType(typeSpecifier.type);
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003308 type->setPrimarySize(typeSpecifier.primarySize);
3309 type->setSecondarySize(typeSpecifier.secondarySize);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003310 type->setPrecision(typeSpecifier.precision);
3311 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04003312 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003313
3314 // don't allow arrays of arrays
Arun Patole7e7e68d2015-05-22 12:02:25 +05303315 if (type->isArray())
3316 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003317 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
3318 recover();
3319 }
3320 if (typeSpecifier.array)
3321 type->setArraySize(typeSpecifier.arraySize);
Arun Patole7e7e68d2015-05-22 12:02:25 +05303322 if (typeSpecifier.userDef)
3323 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003324 type->setStruct(typeSpecifier.userDef->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003325 }
3326
Arun Patole7e7e68d2015-05-22 12:02:25 +05303327 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i]))
3328 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003329 recover();
3330 }
3331 }
3332
Jamie Madill98493dd2013-07-08 14:39:03 -04003333 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003334}
3335
Jamie Madillb98c3a82015-07-23 14:26:04 -04003336TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
3337 const TSourceLoc &nameLine,
3338 const TString *structName,
3339 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003340{
Arun Patole7e7e68d2015-05-22 12:02:25 +05303341 TStructure *structure = new TStructure(structName, fieldList);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003342 TType *structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003343
Jamie Madill9b820842015-02-12 10:40:10 -05003344 // Store a bool in the struct if we're at global scope, to allow us to
3345 // skip the local struct scoping workaround in HLSL.
Jamie Madillb960cc42015-02-12 15:33:20 +00003346 structure->setUniqueId(TSymbolTable::nextUniqueId());
Jamie Madill9b820842015-02-12 10:40:10 -05003347 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04003348
Jamie Madill98493dd2013-07-08 14:39:03 -04003349 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003350 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003351 if (reservedErrorCheck(nameLine, *structName))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003352 {
3353 recover();
3354 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303355 TVariable *userTypeDef = new TVariable(structName, *structureType, true);
3356 if (!symbolTable.declare(userTypeDef))
3357 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003358 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003359 recover();
3360 }
3361 }
3362
3363 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04003364 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003365 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003366 const TField &field = *(*fieldList)[typeListIndex];
Jamie Madill98493dd2013-07-08 14:39:03 -04003367 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003368 switch (qualifier)
3369 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003370 case EvqGlobal:
3371 case EvqTemporary:
3372 break;
3373 default:
3374 error(field.line(), "invalid qualifier on struct member",
3375 getQualifierString(qualifier));
3376 recover();
3377 break;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003378 }
3379 }
3380
3381 TPublicType publicType;
3382 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04003383 publicType.userDef = structureType;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003384 exitStructDeclaration();
3385
3386 return publicType;
3387}
3388
Jamie Madillb98c3a82015-07-23 14:26:04 -04003389TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
3390 TIntermAggregate *statementList,
3391 const TSourceLoc &loc)
Olli Etuahoa3a36662015-02-17 13:46:51 +02003392{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003393 TBasicType switchType = init->getBasicType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003394 if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
Olli Etuaho53f076f2015-02-20 10:55:14 +02003395 init->isVector())
3396 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003397 error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
3398 "switch");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003399 recover();
3400 return nullptr;
3401 }
3402
Olli Etuahoac5274d2015-02-20 10:19:08 +02003403 if (statementList)
3404 {
3405 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
3406 {
3407 recover();
3408 return nullptr;
3409 }
3410 }
3411
Olli Etuahoa3a36662015-02-17 13:46:51 +02003412 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
3413 if (node == nullptr)
3414 {
3415 error(loc, "erroneous switch statement", "switch");
3416 recover();
3417 return nullptr;
3418 }
3419 return node;
3420}
3421
3422TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
3423{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003424 if (mSwitchNestingLevel == 0)
3425 {
3426 error(loc, "case labels need to be inside switch statements", "case");
3427 recover();
3428 return nullptr;
3429 }
3430 if (condition == nullptr)
3431 {
3432 error(loc, "case label must have a condition", "case");
3433 recover();
3434 return nullptr;
3435 }
3436 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
Jamie Madillb98c3a82015-07-23 14:26:04 -04003437 condition->isMatrix() || condition->isArray() || condition->isVector())
Olli Etuaho53f076f2015-02-20 10:55:14 +02003438 {
3439 error(condition->getLine(), "case label must be a scalar integer", "case");
3440 recover();
3441 }
3442 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
3443 if (conditionConst == nullptr)
3444 {
3445 error(condition->getLine(), "case label must be constant", "case");
3446 recover();
3447 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003448 TIntermCase *node = intermediate.addCase(condition, loc);
3449 if (node == nullptr)
3450 {
3451 error(loc, "erroneous case statement", "case");
3452 recover();
3453 return nullptr;
3454 }
3455 return node;
3456}
3457
3458TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
3459{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003460 if (mSwitchNestingLevel == 0)
3461 {
3462 error(loc, "default labels need to be inside switch statements", "default");
3463 recover();
3464 return nullptr;
3465 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003466 TIntermCase *node = intermediate.addCase(nullptr, loc);
3467 if (node == nullptr)
3468 {
3469 error(loc, "erroneous default statement", "default");
3470 recover();
3471 return nullptr;
3472 }
3473 return node;
3474}
3475
Jamie Madillb98c3a82015-07-23 14:26:04 -04003476TIntermTyped *TParseContext::createUnaryMath(TOperator op,
3477 TIntermTyped *child,
3478 const TSourceLoc &loc,
3479 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02003480{
3481 if (child == nullptr)
3482 {
3483 return nullptr;
3484 }
3485
3486 switch (op)
3487 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003488 case EOpLogicalNot:
3489 if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
3490 child->isVector())
3491 {
3492 return nullptr;
3493 }
3494 break;
3495 case EOpBitwiseNot:
3496 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
3497 child->isMatrix() || child->isArray())
3498 {
3499 return nullptr;
3500 }
3501 break;
3502 case EOpPostIncrement:
3503 case EOpPreIncrement:
3504 case EOpPostDecrement:
3505 case EOpPreDecrement:
3506 case EOpNegative:
3507 case EOpPositive:
3508 if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
3509 child->isArray())
3510 {
3511 return nullptr;
3512 }
3513 // Operators for built-ins are already type checked against their prototype.
3514 default:
3515 break;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003516 }
3517
Olli Etuahof6c694b2015-03-26 14:50:53 +02003518 return intermediate.addUnaryMath(op, child, loc, funcReturnType);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003519}
3520
Olli Etuaho09b22472015-02-11 11:47:26 +02003521TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
3522{
Olli Etuahof6c694b2015-03-26 14:50:53 +02003523 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003524 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02003525 {
3526 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
3527 recover();
3528 return child;
3529 }
3530 return node;
3531}
3532
Jamie Madillb98c3a82015-07-23 14:26:04 -04003533TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
3534 TIntermTyped *child,
3535 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003536{
3537 if (lValueErrorCheck(loc, GetOperatorString(op), child))
3538 recover();
3539 return addUnaryMath(op, child, loc);
3540}
3541
Jamie Madillb98c3a82015-07-23 14:26:04 -04003542bool TParseContext::binaryOpCommonCheck(TOperator op,
3543 TIntermTyped *left,
3544 TIntermTyped *right,
3545 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003546{
3547 if (left->isArray() || right->isArray())
3548 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003549 if (mShaderVersion < 300)
Olli Etuahoe79904c2015-03-18 16:56:42 +02003550 {
3551 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3552 return false;
3553 }
3554
3555 if (left->isArray() != right->isArray())
3556 {
3557 error(loc, "array / non-array mismatch", GetOperatorString(op));
3558 return false;
3559 }
3560
3561 switch (op)
3562 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003563 case EOpEqual:
3564 case EOpNotEqual:
3565 case EOpAssign:
3566 case EOpInitialize:
3567 break;
3568 default:
3569 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3570 return false;
Olli Etuahoe79904c2015-03-18 16:56:42 +02003571 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03003572 // At this point, size of implicitly sized arrays should be resolved.
Olli Etuahoe79904c2015-03-18 16:56:42 +02003573 if (left->getArraySize() != right->getArraySize())
3574 {
3575 error(loc, "array size mismatch", GetOperatorString(op));
3576 return false;
3577 }
Olli Etuahod6b14282015-03-17 14:31:35 +02003578 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003579
3580 // Check ops which require integer / ivec parameters
3581 bool isBitShift = false;
3582 switch (op)
3583 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003584 case EOpBitShiftLeft:
3585 case EOpBitShiftRight:
3586 case EOpBitShiftLeftAssign:
3587 case EOpBitShiftRightAssign:
3588 // Unsigned can be bit-shifted by signed and vice versa, but we need to
3589 // check that the basic type is an integer type.
3590 isBitShift = true;
3591 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
3592 {
3593 return false;
3594 }
3595 break;
3596 case EOpBitwiseAnd:
3597 case EOpBitwiseXor:
3598 case EOpBitwiseOr:
3599 case EOpBitwiseAndAssign:
3600 case EOpBitwiseXorAssign:
3601 case EOpBitwiseOrAssign:
3602 // It is enough to check the type of only one operand, since later it
3603 // is checked that the operand types match.
3604 if (!IsInteger(left->getBasicType()))
3605 {
3606 return false;
3607 }
3608 break;
3609 default:
3610 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003611 }
3612
3613 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
3614 // So the basic type should usually match.
3615 if (!isBitShift && left->getBasicType() != right->getBasicType())
3616 {
3617 return false;
3618 }
3619
Olli Etuaho9dd217b2015-03-20 14:24:31 +02003620 // Check that type sizes match exactly on ops that require that.
Olli Etuahoff699002015-03-23 14:38:42 +02003621 // Also check restrictions for structs that contain arrays or samplers.
Jamie Madillb98c3a82015-07-23 14:26:04 -04003622 switch (op)
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003623 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003624 case EOpAssign:
3625 case EOpInitialize:
3626 case EOpEqual:
3627 case EOpNotEqual:
3628 // ESSL 1.00 sections 5.7, 5.8, 5.9
3629 if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
3630 {
3631 error(loc, "undefined operation for structs containing arrays",
3632 GetOperatorString(op));
3633 return false;
3634 }
3635 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
3636 // we interpret the spec so that this extends to structs containing samplers,
3637 // similarly to ESSL 1.00 spec.
3638 if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
3639 left->getType().isStructureContainingSamplers())
3640 {
3641 error(loc, "undefined operation for structs containing samplers",
3642 GetOperatorString(op));
3643 return false;
3644 }
3645 case EOpLessThan:
3646 case EOpGreaterThan:
3647 case EOpLessThanEqual:
3648 case EOpGreaterThanEqual:
3649 if ((left->getNominalSize() != right->getNominalSize()) ||
3650 (left->getSecondarySize() != right->getSecondarySize()))
3651 {
3652 return false;
3653 }
3654 default:
3655 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003656 }
3657
Olli Etuahod6b14282015-03-17 14:31:35 +02003658 return true;
3659}
3660
Jamie Madillb98c3a82015-07-23 14:26:04 -04003661TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
3662 TIntermTyped *left,
3663 TIntermTyped *right,
3664 const TSourceLoc &loc)
Olli Etuahofc1806e2015-03-17 13:03:11 +02003665{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003666 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003667 return nullptr;
3668
Olli Etuahofc1806e2015-03-17 13:03:11 +02003669 switch (op)
3670 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003671 case EOpEqual:
3672 case EOpNotEqual:
3673 break;
3674 case EOpLessThan:
3675 case EOpGreaterThan:
3676 case EOpLessThanEqual:
3677 case EOpGreaterThanEqual:
3678 ASSERT(!left->isArray() && !right->isArray());
3679 if (left->isMatrix() || left->isVector() || left->getBasicType() == EbtStruct)
3680 {
3681 return nullptr;
3682 }
3683 break;
3684 case EOpLogicalOr:
3685 case EOpLogicalXor:
3686 case EOpLogicalAnd:
3687 ASSERT(!left->isArray() && !right->isArray());
3688 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
3689 {
3690 return nullptr;
3691 }
3692 break;
3693 case EOpAdd:
3694 case EOpSub:
3695 case EOpDiv:
3696 case EOpMul:
3697 ASSERT(!left->isArray() && !right->isArray());
3698 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
3699 {
3700 return nullptr;
3701 }
3702 break;
3703 case EOpIMod:
3704 ASSERT(!left->isArray() && !right->isArray());
3705 // Note that this is only for the % operator, not for mod()
3706 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool ||
3707 left->getBasicType() == EbtFloat)
3708 {
3709 return nullptr;
3710 }
3711 break;
3712 // Note that for bitwise ops, type checking is done in promote() to
3713 // share code between ops and compound assignment
3714 default:
3715 break;
Olli Etuahofc1806e2015-03-17 13:03:11 +02003716 }
3717
Olli Etuahofc1806e2015-03-17 13:03:11 +02003718 return intermediate.addBinaryMath(op, left, right, loc);
3719}
3720
Jamie Madillb98c3a82015-07-23 14:26:04 -04003721TIntermTyped *TParseContext::addBinaryMath(TOperator op,
3722 TIntermTyped *left,
3723 TIntermTyped *right,
3724 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003725{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003726 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003727 if (node == 0)
3728 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003729 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3730 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003731 recover();
3732 return left;
3733 }
3734 return node;
3735}
3736
Jamie Madillb98c3a82015-07-23 14:26:04 -04003737TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
3738 TIntermTyped *left,
3739 TIntermTyped *right,
3740 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003741{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003742 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003743 if (node == 0)
3744 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003745 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3746 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003747 recover();
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003748 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuaho09b22472015-02-11 11:47:26 +02003749 unionArray->setBConst(false);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003750 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
3751 loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003752 }
3753 return node;
3754}
3755
Jamie Madillb98c3a82015-07-23 14:26:04 -04003756TIntermTyped *TParseContext::createAssign(TOperator op,
3757 TIntermTyped *left,
3758 TIntermTyped *right,
3759 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003760{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003761 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003762 {
3763 return intermediate.addAssign(op, left, right, loc);
3764 }
3765 return nullptr;
3766}
3767
Jamie Madillb98c3a82015-07-23 14:26:04 -04003768TIntermTyped *TParseContext::addAssign(TOperator op,
3769 TIntermTyped *left,
3770 TIntermTyped *right,
3771 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003772{
3773 TIntermTyped *node = createAssign(op, left, right, loc);
3774 if (node == nullptr)
3775 {
3776 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
3777 recover();
3778 return left;
3779 }
3780 return node;
3781}
3782
Olli Etuaho49300862015-02-20 14:54:49 +02003783TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
3784{
3785 switch (op)
3786 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003787 case EOpContinue:
3788 if (mLoopNestingLevel <= 0)
3789 {
3790 error(loc, "continue statement only allowed in loops", "");
3791 recover();
3792 }
3793 break;
3794 case EOpBreak:
3795 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
3796 {
3797 error(loc, "break statement only allowed in loops and switch statements", "");
3798 recover();
3799 }
3800 break;
3801 case EOpReturn:
3802 if (mCurrentFunctionType->getBasicType() != EbtVoid)
3803 {
3804 error(loc, "non-void function must return a value", "return");
3805 recover();
3806 }
3807 break;
3808 default:
3809 // No checks for discard
3810 break;
Olli Etuaho49300862015-02-20 14:54:49 +02003811 }
3812 return intermediate.addBranch(op, loc);
3813}
3814
Jamie Madillb98c3a82015-07-23 14:26:04 -04003815TIntermBranch *TParseContext::addBranch(TOperator op,
3816 TIntermTyped *returnValue,
3817 const TSourceLoc &loc)
Olli Etuaho49300862015-02-20 14:54:49 +02003818{
3819 ASSERT(op == EOpReturn);
3820 mFunctionReturnsValue = true;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003821 if (mCurrentFunctionType->getBasicType() == EbtVoid)
Olli Etuaho49300862015-02-20 14:54:49 +02003822 {
3823 error(loc, "void function cannot return a value", "return");
3824 recover();
3825 }
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003826 else if (*mCurrentFunctionType != returnValue->getType())
Olli Etuaho49300862015-02-20 14:54:49 +02003827 {
3828 error(loc, "function return is not matching type:", "return");
3829 recover();
3830 }
3831 return intermediate.addBranch(op, returnValue, loc);
3832}
3833
Jamie Madillb98c3a82015-07-23 14:26:04 -04003834TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
3835 TIntermNode *paramNode,
3836 TIntermNode *thisNode,
3837 const TSourceLoc &loc,
3838 bool *fatalError)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003839{
Jamie Madillb98c3a82015-07-23 14:26:04 -04003840 *fatalError = false;
3841 TOperator op = fnCall->getBuiltInOp();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003842 TIntermTyped *callNode = nullptr;
3843
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003844 if (thisNode != nullptr)
3845 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003846 TConstantUnion *unionArray = new TConstantUnion[1];
Jamie Madillb98c3a82015-07-23 14:26:04 -04003847 int arraySize = 0;
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003848 TIntermTyped *typedThis = thisNode->getAsTyped();
3849 if (fnCall->getName() != "length")
3850 {
3851 error(loc, "invalid method", fnCall->getName().c_str());
3852 recover();
3853 }
3854 else if (paramNode != nullptr)
3855 {
3856 error(loc, "method takes no parameters", "length");
3857 recover();
3858 }
3859 else if (typedThis == nullptr || !typedThis->isArray())
3860 {
3861 error(loc, "length can only be called on arrays", "length");
3862 recover();
3863 }
3864 else
3865 {
Olli Etuaho96e67382015-04-23 14:27:02 +03003866 arraySize = typedThis->getArraySize();
Olli Etuaho39282e12015-04-23 15:41:48 +03003867 if (typedThis->getAsSymbolNode() == nullptr)
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003868 {
Olli Etuaho39282e12015-04-23 15:41:48 +03003869 // This code path can be hit with expressions like these:
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003870 // (a = b).length()
Olli Etuaho39282e12015-04-23 15:41:48 +03003871 // (func()).length()
3872 // (int[3](0, 1, 2)).length()
Jamie Madillb98c3a82015-07-23 14:26:04 -04003873 // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
3874 // expression.
3875 // It allows "An array name with the length method applied" in contrast to GLSL 4.4
3876 // spec section 5.9 which allows "An array, vector or matrix expression with the
3877 // length method applied".
3878 error(loc, "length can only be called on array names, not on array expressions",
3879 "length");
Olli Etuaho39282e12015-04-23 15:41:48 +03003880 recover();
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003881 }
3882 }
Olli Etuaho96e67382015-04-23 14:27:02 +03003883 unionArray->setIConst(arraySize);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003884 callNode =
3885 intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003886 }
3887 else if (op != EOpNull)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003888 {
3889 //
3890 // Then this should be a constructor.
3891 // Don't go through the symbol table for constructors.
3892 // Their parameters will be verified algorithmically.
3893 //
3894 TType type(EbtVoid, EbpUndefined); // use this to get the type back
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003895 if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type))
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003896 {
3897 //
3898 // It's a constructor, of type 'type'.
3899 //
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003900 callNode = addConstructor(paramNode, &type, op, fnCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003901 }
Olli Etuaho72ba85b2015-03-04 14:23:26 +02003902
3903 if (callNode == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003904 {
3905 recover();
3906 callNode = intermediate.setAggregateOperator(nullptr, op, loc);
3907 }
3908 callNode->setType(type);
3909 }
3910 else
3911 {
3912 //
3913 // Not a constructor. Find it in the symbol table.
3914 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303915 const TFunction *fnCandidate;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003916 bool builtIn;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003917 fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003918 if (fnCandidate)
3919 {
3920 //
3921 // A declared function.
3922 //
3923 if (builtIn && !fnCandidate->getExtension().empty() &&
3924 extensionErrorCheck(loc, fnCandidate->getExtension()))
3925 {
3926 recover();
3927 }
3928 op = fnCandidate->getBuiltInOp();
3929 if (builtIn && op != EOpNull)
3930 {
3931 //
3932 // A function call mapped to a built-in operation.
3933 //
3934 if (fnCandidate->getParamCount() == 1)
3935 {
3936 //
3937 // Treat it like a built-in unary operator.
3938 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04003939 callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
3940 &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003941 if (callNode == nullptr)
3942 {
3943 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003944 extraInfoStream
3945 << "built in unary operator function. Type: "
3946 << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003947 std::string extraInfo = extraInfoStream.str();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003948 error(paramNode->getLine(), " wrong operand type", "Internal Error",
3949 extraInfo.c_str());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003950 *fatalError = true;
3951 return nullptr;
3952 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003953 }
3954 else
3955 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003956 TIntermAggregate *aggregate =
3957 intermediate.setAggregateOperator(paramNode, op, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003958 aggregate->setType(fnCandidate->getReturnType());
3959 aggregate->setPrecisionFromChildren();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003960
3961 // Some built-in functions have out parameters too.
3962 functionCallLValueErrorCheck(fnCandidate, aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303963
3964 // See if we can constant fold a built-in.
Olli Etuahob43846e2015-06-02 18:18:57 +03003965 TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303966 if (foldedNode)
3967 {
Arun Patole274f0702015-05-05 13:33:30 +05303968 callNode = foldedNode;
3969 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003970 else
3971 {
3972 callNode = aggregate;
3973 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003974 }
3975 }
3976 else
3977 {
3978 // This is a real function call
3979
Jamie Madillb98c3a82015-07-23 14:26:04 -04003980 TIntermAggregate *aggregate =
3981 intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003982 aggregate->setType(fnCandidate->getReturnType());
3983
Jamie Madillb98c3a82015-07-23 14:26:04 -04003984 // this is how we know whether the given function is a builtIn function or a user
3985 // defined function
3986 // if builtIn == false, it's a userDefined -> could be an overloaded
3987 // builtIn function also
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003988 // if builtIn == true, it's definitely a builtIn function with EOpNull
3989 if (!builtIn)
3990 aggregate->setUserDefined();
3991 aggregate->setName(fnCandidate->getMangledName());
Corentin Wallez71d147f2015-02-11 11:15:24 -08003992 aggregate->setFunctionId(fnCandidate->getUniqueId());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003993
3994 // This needs to happen after the name is set
3995 if (builtIn)
3996 aggregate->setBuiltInFunctionPrecision();
3997
3998 callNode = aggregate;
3999
4000 functionCallLValueErrorCheck(fnCandidate, aggregate);
4001 }
4002 }
4003 else
4004 {
4005 // error message was put out by findFunction()
4006 // Put on a dummy node for error recovery
Jamie Madill6ba6ead2015-05-04 14:21:21 -04004007 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004008 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04004009 callNode = intermediate.addConstantUnion(unionArray,
4010 TType(EbtFloat, EbpUndefined, EvqConst), loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004011 recover();
4012 }
4013 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02004014 return callNode;
4015}
4016
Jamie Madillb98c3a82015-07-23 14:26:04 -04004017TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
4018 TIntermTyped *trueBlock,
4019 TIntermTyped *falseBlock,
Olli Etuaho52901742015-04-15 13:42:45 +03004020 const TSourceLoc &loc)
4021{
4022 if (boolErrorCheck(loc, cond))
4023 recover();
4024
4025 if (trueBlock->getType() != falseBlock->getType())
4026 {
4027 binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
4028 recover();
4029 return falseBlock;
4030 }
Olli Etuahoa2d53032015-04-15 14:14:44 +03004031 // ESSL1 sections 5.2 and 5.7:
4032 // ESSL3 section 5.7:
4033 // Ternary operator is not among the operators allowed for structures/arrays.
4034 if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
4035 {
4036 error(loc, "ternary operator is not allowed for structures or arrays", ":");
4037 recover();
4038 return falseBlock;
4039 }
Olli Etuaho52901742015-04-15 13:42:45 +03004040 return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
4041}
Olli Etuaho49300862015-02-20 14:54:49 +02004042
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00004043//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004044// Parse an array of strings using yyparse.
4045//
4046// Returns 0 for success.
4047//
Jamie Madillb98c3a82015-07-23 14:26:04 -04004048int PaParseStrings(size_t count,
4049 const char *const string[],
4050 const int length[],
Arun Patole7e7e68d2015-05-22 12:02:25 +05304051 TParseContext *context)
4052{
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004053 if ((count == 0) || (string == NULL))
4054 return 1;
4055
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004056 if (glslang_initialize(context))
4057 return 1;
4058
alokp@chromium.org408c45e2012-04-05 15:54:43 +00004059 int error = glslang_scan(count, string, length, context);
4060 if (!error)
4061 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004062
alokp@chromium.org73bc2982012-06-19 18:48:05 +00004063 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00004064
alokp@chromium.org6b495712012-06-29 00:06:58 +00004065 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004066}