blob: 8eaa1110d2a022c26e89fbc866be2d804b0a9edd [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//
131// Errors
132//
133////////////////////////////////////////////////////////////////////////
134
135//
136// Track whether errors have occurred.
137//
138void TParseContext::recover()
139{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140}
141
142//
143// Used by flex/bison to output all syntax and parsing errors.
144//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530145void TParseContext::error(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400146 const char *reason,
147 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530148 const char *extraInfo)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000150 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400151 srcLoc.file = loc.first_file;
152 srcLoc.line = loc.first_line;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400153 mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154}
155
Arun Patole7e7e68d2015-05-22 12:02:25 +0530156void TParseContext::warning(const TSourceLoc &loc,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400157 const char *reason,
158 const char *token,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530159 const char *extraInfo)
160{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000161 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400162 srcLoc.file = loc.first_file;
163 srcLoc.line = loc.first_line;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400164 mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000165}
166
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167//
168// Same error message for all places assignments don't work.
169//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530170void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000172 std::stringstream extraInfoStream;
173 extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
174 std::string extraInfo = extraInfoStream.str();
175 error(line, "", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176}
177
178//
179// Same error message for all places unary operations don't work.
180//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530181void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000183 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400184 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type "
185 << operand << " (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000186 std::string extraInfo = extraInfoStream.str();
187 error(line, " wrong operand type", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188}
189
190//
191// Same error message for all binary operations don't work.
192//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400193void TParseContext::binaryOpError(const TSourceLoc &line,
194 const char *op,
195 TString left,
196 TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000198 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400199 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '"
200 << left << "' and a right operand of type '" << right
201 << "' (or there is no acceptable conversion)";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000202 std::string extraInfo = extraInfoStream.str();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530203 error(line, " wrong operand types ", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204}
205
Jamie Madillb98c3a82015-07-23 14:26:04 -0400206bool TParseContext::precisionErrorCheck(const TSourceLoc &line,
207 TPrecision precision,
208 TBasicType type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530209{
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400210 if (!mChecksPrecisionErrors)
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000211 return false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400212 switch (type)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530213 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400214 case EbtFloat:
215 if (precision == EbpUndefined)
216 {
217 error(line, "No precision specified for (float)", "");
218 return true;
219 }
220 break;
221 case EbtInt:
222 if (precision == EbpUndefined)
223 {
224 error(line, "No precision specified (int)", "");
225 return true;
226 }
227 break;
228 default:
229 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000230 }
231 return false;
232}
233
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234//
235// Both test and if necessary, spit out an error, to see if the node is really
236// an l-value that can be operated on this way.
237//
238// Returns true if the was an error.
239//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530240bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400242 TIntermSymbol *symNode = node->getAsSymbolNode();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530243 TIntermBinary *binaryNode = node->getAsBinaryNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000244
Arun Patole7e7e68d2015-05-22 12:02:25 +0530245 if (binaryNode)
246 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000247 bool errorReturn;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248
Jamie Madillb98c3a82015-07-23 14:26:04 -0400249 switch (binaryNode->getOp())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530250 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400251 case EOpIndexDirect:
252 case EOpIndexIndirect:
253 case EOpIndexDirectStruct:
254 case EOpIndexDirectInterfaceBlock:
255 return lValueErrorCheck(line, op, binaryNode->getLeft());
256 case EOpVectorSwizzle:
257 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
258 if (!errorReturn)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530259 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400260 int offset[4] = {0, 0, 0, 0};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261
Jamie Madillb98c3a82015-07-23 14:26:04 -0400262 TIntermTyped *rightNode = binaryNode->getRight();
263 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
264
265 for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
266 p != aggrNode->getSequence()->end(); p++)
267 {
268 int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
269 offset[value]++;
270 if (offset[value] > 1)
271 {
272 error(line, " l-value of swizzle cannot have duplicate components", op);
273
274 return true;
275 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000276 }
277 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278
Jamie Madillb98c3a82015-07-23 14:26:04 -0400279 return errorReturn;
280 default:
281 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000282 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000283 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000285 return true;
286 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287
Arun Patole7e7e68d2015-05-22 12:02:25 +0530288 const char *symbol = 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000289 if (symNode != 0)
290 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291
Arun Patole7e7e68d2015-05-22 12:02:25 +0530292 const char *message = 0;
293 switch (node->getQualifier())
294 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400295 case EvqConst:
296 message = "can't modify a const";
297 break;
298 case EvqConstReadOnly:
299 message = "can't modify a const";
300 break;
301 case EvqAttribute:
302 message = "can't modify an attribute";
303 break;
304 case EvqFragmentIn:
305 message = "can't modify an input";
306 break;
307 case EvqVertexIn:
308 message = "can't modify an input";
309 break;
310 case EvqUniform:
311 message = "can't modify a uniform";
312 break;
313 case EvqVaryingIn:
314 message = "can't modify a varying";
315 break;
316 case EvqFragCoord:
317 message = "can't modify gl_FragCoord";
318 break;
319 case EvqFrontFacing:
320 message = "can't modify gl_FrontFacing";
321 break;
322 case EvqPointCoord:
323 message = "can't modify gl_PointCoord";
324 break;
325 default:
326 //
327 // Type that can't be written to?
328 //
329 if (node->getBasicType() == EbtVoid)
330 {
331 message = "can't modify void";
332 }
333 if (IsSampler(node->getBasicType()))
334 {
335 message = "can't modify a sampler";
336 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000337 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338
Arun Patole7e7e68d2015-05-22 12:02:25 +0530339 if (message == 0 && binaryNode == 0 && symNode == 0)
340 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000341 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000343 return true;
344 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000346 //
347 // Everything else is okay, no error.
348 //
349 if (message == 0)
350 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000352 //
353 // If we get here, we have an error and a message.
354 //
Arun Patole7e7e68d2015-05-22 12:02:25 +0530355 if (symNode)
356 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000357 std::stringstream extraInfoStream;
358 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
359 std::string extraInfo = extraInfoStream.str();
360 error(line, " l-value required", op, extraInfo.c_str());
361 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530362 else
363 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000364 std::stringstream extraInfoStream;
365 extraInfoStream << "(" << message << ")";
366 std::string extraInfo = extraInfoStream.str();
367 error(line, " l-value required", op, extraInfo.c_str());
368 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000370 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371}
372
373//
374// Both test, and if necessary spit out an error, to see if the node is really
375// a constant.
376//
377// Returns true if the was an error.
378//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530379bool TParseContext::constErrorCheck(TIntermTyped *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000380{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000381 if (node->getQualifier() == EvqConst)
382 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000384 error(node->getLine(), "constant expression required", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000386 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387}
388
389//
390// Both test, and if necessary spit out an error, to see if the node is really
391// an integer.
392//
393// Returns true if the was an error.
394//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530395bool TParseContext::integerErrorCheck(TIntermTyped *node, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396{
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000397 if (node->isScalarInt())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000398 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000399
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000400 error(node->getLine(), "integer expression required", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000402 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403}
404
405//
406// Both test, and if necessary spit out an error, to see if we are currently
407// globally scoped.
408//
409// Returns true if the was an error.
410//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530411bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char *token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000412{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000413 if (global)
414 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000416 error(line, "only allowed at global scope", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000417
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000418 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419}
420
421//
422// For now, keep it simple: if it starts "gl_", it's reserved, independent
423// of scope. Except, if the symbol table is at the built-in push-level,
424// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000425// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
426// webgl shader.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427//
428// Returns true if there was an error.
429//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530430bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530432 static const char *reservedErrMsg = "reserved built-in name";
433 if (!symbolTable.atBuiltInLevel())
434 {
435 if (identifier.compare(0, 3, "gl_") == 0)
436 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000437 error(line, reservedErrMsg, "gl_");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000438 return true;
439 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530440 if (IsWebGLBasedSpec(mShaderSpec))
441 {
442 if (identifier.compare(0, 6, "webgl_") == 0)
443 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000444 error(line, reservedErrMsg, "webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000445 return true;
446 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530447 if (identifier.compare(0, 7, "_webgl_") == 0)
448 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000449 error(line, reservedErrMsg, "_webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000450 return true;
451 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530452 if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0)
453 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000454 error(line, reservedErrMsg, "css_");
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000455 return true;
456 }
alokp@chromium.org613ef312010-07-21 18:54:22 +0000457 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530458 if (identifier.find("__") != TString::npos)
459 {
460 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400461 "identifiers containing two consecutive underscores (__) are reserved as "
462 "possible future keywords",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530463 identifier.c_str());
daniel@transgaming.combeadd5d2012-04-12 02:35:31 +0000464 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000465 }
466 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000468 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469}
470
471//
472// Make sure there is enough data provided to the constructor to build
473// something of the type of the constructor. Also returns the type of
474// the constructor.
475//
476// Returns true if there was an error in construction.
477//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400478bool TParseContext::constructorErrorCheck(const TSourceLoc &line,
479 TIntermNode *node,
480 TFunction &function,
481 TOperator op,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530482 TType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000484 *type = function.getReturnType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000486 bool constructingMatrix = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -0400487 switch (op)
Arun Patole7e7e68d2015-05-22 12:02:25 +0530488 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400489 case EOpConstructMat2:
490 case EOpConstructMat2x3:
491 case EOpConstructMat2x4:
492 case EOpConstructMat3x2:
493 case EOpConstructMat3:
494 case EOpConstructMat3x4:
495 case EOpConstructMat4x2:
496 case EOpConstructMat4x3:
497 case EOpConstructMat4:
498 constructingMatrix = true;
499 break;
500 default:
501 break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000502 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000504 //
505 // Note: It's okay to have too many components available, but not okay to have unused
506 // arguments. 'full' will go to true when enough args have been seen. If we loop
507 // again, there is an extra argument, so 'overfull' will become true.
508 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509
Jamie Madillb98c3a82015-07-23 14:26:04 -0400510 size_t size = 0;
511 bool constType = true;
512 bool full = false;
513 bool overFull = false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000514 bool matrixInMatrix = false;
515 bool arrayArg = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530516 for (size_t i = 0; i < function.getParamCount(); ++i)
517 {
Dmitry Skibaefa3d8e2015-06-22 14:52:10 -0700518 const TConstParameter &param = function.getParam(i);
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000519 size += param.type->getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +0530520
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000521 if (constructingMatrix && param.type->isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000522 matrixInMatrix = true;
523 if (full)
524 overFull = true;
525 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
526 full = true;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000527 if (param.type->getQualifier() != EvqConst)
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000528 constType = false;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000529 if (param.type->isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000530 arrayArg = true;
531 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530532
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000533 if (constType)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000534 type->setQualifier(EvqConst);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000535
Olli Etuaho376f1b52015-04-13 13:23:41 +0300536 if (type->isArray())
537 {
538 if (type->isUnsizedArray())
539 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700540 type->setArraySize(static_cast<int>(function.getParamCount()));
Olli Etuaho376f1b52015-04-13 13:23:41 +0300541 }
542 else if (static_cast<size_t>(type->getArraySize()) != function.getParamCount())
543 {
544 error(line, "array constructor needs one argument per array element", "constructor");
545 return true;
546 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000547 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548
Arun Patole7e7e68d2015-05-22 12:02:25 +0530549 if (arrayArg && op != EOpConstructStruct)
550 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000551 error(line, "constructing from a non-dereferenced array", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000552 return true;
553 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000554
Arun Patole7e7e68d2015-05-22 12:02:25 +0530555 if (matrixInMatrix && !type->isArray())
556 {
557 if (function.getParamCount() != 1)
558 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400559 error(line, "constructing matrix from matrix can only take one argument",
560 "constructor");
561 return true;
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000562 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000563 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564
Arun Patole7e7e68d2015-05-22 12:02:25 +0530565 if (overFull)
566 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000567 error(line, "too many arguments", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000568 return true;
569 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530570
Jamie Madillb98c3a82015-07-23 14:26:04 -0400571 if (op == EOpConstructStruct && !type->isArray() &&
572 type->getStruct()->fields().size() != function.getParamCount())
Arun Patole7e7e68d2015-05-22 12:02:25 +0530573 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400574 error(line,
575 "Number of constructor parameters does not match the number of structure fields",
576 "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000577 return true;
578 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579
Arun Patole7e7e68d2015-05-22 12:02:25 +0530580 if (!type->isMatrix() || !matrixInMatrix)
581 {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000582 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
Arun Patole7e7e68d2015-05-22 12:02:25 +0530583 (op == EOpConstructStruct && size < type->getObjectSize()))
584 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000585 error(line, "not enough data provided for construction", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000586 return true;
587 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000588 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000589
daniel@transgaming.com0b53fc02011-03-09 15:12:12 +0000590 TIntermTyped *typed = node ? node->getAsTyped() : 0;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530591 if (typed == 0)
592 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000593 error(line, "constructor argument does not have a type", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000594 return true;
595 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530596 if (op != EOpConstructStruct && IsSampler(typed->getBasicType()))
597 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000598 error(line, "cannot convert a sampler", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000599 return true;
600 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530601 if (typed->getBasicType() == EbtVoid)
602 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000603 error(line, "cannot convert a void", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000604 return true;
605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000607 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608}
609
Jamie Madillb98c3a82015-07-23 14:26:04 -0400610// This function checks to see if a void variable has been declared and raise an error message for
611// such a case
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612//
613// returns true in case of an error
614//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400615bool TParseContext::voidErrorCheck(const TSourceLoc &line,
616 const TString &identifier,
617 const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000618{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300619 if (type == EbtVoid)
620 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000621 error(line, "illegal use of type 'void'", identifier.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000622 return true;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300623 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000625 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626}
627
Jamie Madillb98c3a82015-07-23 14:26:04 -0400628// This function checks to see if the node (for the expression) contains a scalar boolean expression
629// or not
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630//
631// returns true in case of an error
632//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530633bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TIntermTyped *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530635 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
636 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000637 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000638 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530639 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000641 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642}
643
Jamie Madillb98c3a82015-07-23 14:26:04 -0400644// This function checks to see if the node (for the expression) contains a scalar boolean expression
645// or not
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646//
647// returns true in case of an error
648//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530649bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TPublicType &pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530651 if (pType.type != EbtBool || pType.isAggregate())
652 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000653 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000654 return true;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530655 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000657 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658}
659
Jamie Madillb98c3a82015-07-23 14:26:04 -0400660bool TParseContext::samplerErrorCheck(const TSourceLoc &line,
661 const TPublicType &pType,
662 const char *reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530664 if (pType.type == EbtStruct)
665 {
666 if (containsSampler(*pType.userDef))
667 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000668 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
Arun Patole7e7e68d2015-05-22 12:02:25 +0530669
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000670 return true;
671 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530672
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000673 return false;
Arun Patole7e7e68d2015-05-22 12:02:25 +0530674 }
675 else if (IsSampler(pType.type))
676 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000677 error(line, reason, getBasicString(pType.type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000679 return true;
680 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000681
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000682 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000683}
684
Arun Patole7e7e68d2015-05-22 12:02:25 +0530685bool TParseContext::locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400686{
687 if (pType.layoutQualifier.location != -1)
688 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400689 error(line, "location must only be specified for a single input or output variable",
690 "location");
Jamie Madill0bd18df2013-06-20 11:55:52 -0400691 return true;
692 }
693
694 return false;
695}
696
Jamie Madillb98c3a82015-07-23 14:26:04 -0400697bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line,
698 TQualifier qualifier,
699 const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000700{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400701 if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct &&
702 IsSampler(type.getBasicType()))
Arun Patole7e7e68d2015-05-22 12:02:25 +0530703 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000704 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000705 return true;
706 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000708 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000709}
710
Arun Patole7e7e68d2015-05-22 12:02:25 +0530711bool TParseContext::containsSampler(const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000712{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000713 if (IsSampler(type.getBasicType()))
714 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000715
Arun Patole7e7e68d2015-05-22 12:02:25 +0530716 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
717 {
718 const TFieldList &fields = type.getStruct()->fields();
719 for (unsigned int i = 0; i < fields.size(); ++i)
720 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400721 if (containsSampler(*fields[i]->type()))
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000722 return true;
723 }
724 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000725
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000726 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727}
728
729//
730// Do size checking for an array type's size.
731//
732// Returns true if there was an error.
733//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530734bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000735{
Arun Patole7e7e68d2015-05-22 12:02:25 +0530736 TIntermConstantUnion *constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000737
Olli Etuahoe7847b02015-03-16 11:56:12 +0200738 if (constant == nullptr || !constant->isScalarInt())
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000739 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000740 error(line, "array size must be a constant integer expression", "");
Olli Etuahoe7847b02015-03-16 11:56:12 +0200741 size = 1;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000742 return true;
743 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000744
Nicolas Capens906744a2014-06-06 15:18:07 -0400745 unsigned int unsignedSize = 0;
746
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000747 if (constant->getBasicType() == EbtUInt)
748 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400749 unsignedSize = constant->getUConst(0);
Jamie Madillb98c3a82015-07-23 14:26:04 -0400750 size = static_cast<int>(unsignedSize);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000751 }
752 else
753 {
754 size = constant->getIConst(0);
755
Nicolas Capens906744a2014-06-06 15:18:07 -0400756 if (size < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000757 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400758 error(line, "array size must be non-negative", "");
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000759 size = 1;
760 return true;
761 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400762
763 unsignedSize = static_cast<unsigned int>(size);
764 }
765
766 if (size == 0)
767 {
768 error(line, "array size must be greater than zero", "");
769 size = 1;
770 return true;
771 }
772
773 // The size of arrays is restricted here to prevent issues further down the
774 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
775 // 4096 registers so this should be reasonable even for aggressively optimizable code.
776 const unsigned int sizeLimit = 65536;
777
778 if (unsignedSize > sizeLimit)
779 {
780 error(line, "array size too large", "");
781 size = 1;
782 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000783 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000785 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000786}
787
788//
789// See if this qualifier can be an array.
790//
791// Returns true if there is an error.
792//
Olli Etuaho3739d232015-04-08 12:23:44 +0300793bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000794{
Olli Etuaho3739d232015-04-08 12:23:44 +0300795 if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) ||
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400796 (type.qualifier == EvqConst && mShaderVersion < 300))
Olli Etuaho3739d232015-04-08 12:23:44 +0300797 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400798 error(line, "cannot declare arrays of this qualifier",
799 TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000800 return true;
801 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000802
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000803 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804}
805
806//
807// See if this type can be an array.
808//
809// Returns true if there is an error.
810//
Arun Patole7e7e68d2015-05-22 12:02:25 +0530811bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000813 //
814 // Can the type be an array?
815 //
Jamie Madill06145232015-05-13 13:10:01 -0400816 if (type.array)
817 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000818 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000819 return true;
820 }
Olli Etuahocc36b982015-07-10 14:14:18 +0300821 // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
822 // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
823 // 4.3.4).
824 if (mShaderVersion >= 300 && type.type == EbtStruct && sh::IsVarying(type.qualifier))
825 {
826 error(line, "cannot declare arrays of structs of this qualifier",
827 TType(type).getCompleteString().c_str());
828 return true;
829 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000830
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000831 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000832}
833
834//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835// Enforce non-initializer type/qualifier rules.
836//
837// Returns true if there was an error.
838//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400839bool TParseContext::nonInitErrorCheck(const TSourceLoc &line,
840 const TString &identifier,
841 TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000842{
Olli Etuaho3739d232015-04-08 12:23:44 +0300843 ASSERT(type != nullptr);
844 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000845 {
846 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +0300847 type->qualifier = EvqTemporary;
848
849 // Generate informative error messages for ESSL1.
850 // In ESSL3 arrays and structures containing arrays can be constant.
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400851 if (mShaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000852 {
Arun Patole7e7e68d2015-05-22 12:02:25 +0530853 error(line,
Jamie Madillb98c3a82015-07-23 14:26:04 -0400854 "structures containing arrays may not be declared constant since they cannot be "
855 "initialized",
Arun Patole7e7e68d2015-05-22 12:02:25 +0530856 identifier.c_str());
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000857 }
858 else
859 {
860 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
861 }
862
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000863 return true;
864 }
Olli Etuaho376f1b52015-04-13 13:23:41 +0300865 if (type->isUnsizedArray())
866 {
867 error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
868 return true;
869 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000870 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871}
872
Olli Etuaho2935c582015-04-08 14:32:06 +0300873// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874// and update the symbol table.
875//
Olli Etuaho2935c582015-04-08 14:32:06 +0300876// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000877//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400878bool TParseContext::declareVariable(const TSourceLoc &line,
879 const TString &identifier,
880 const TType &type,
Olli Etuaho2935c582015-04-08 14:32:06 +0300881 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000882{
Olli Etuaho2935c582015-04-08 14:32:06 +0300883 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000884
Olli Etuaho2935c582015-04-08 14:32:06 +0300885 bool needsReservedErrorCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000886
Olli Etuaho2935c582015-04-08 14:32:06 +0300887 // gl_LastFragData may be redeclared with a new precision qualifier
888 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
889 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400890 const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
891 symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
Olli Etuaho2935c582015-04-08 14:32:06 +0300892 if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst())
893 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -0400894 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
Olli Etuaho2935c582015-04-08 14:32:06 +0300895 {
896 needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
897 }
898 }
899 else
900 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400901 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
902 identifier.c_str());
Olli Etuaho2935c582015-04-08 14:32:06 +0300903 return false;
904 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000905 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906
Olli Etuaho2935c582015-04-08 14:32:06 +0300907 if (needsReservedErrorCheck && reservedErrorCheck(line, identifier))
908 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000909
Olli Etuaho2935c582015-04-08 14:32:06 +0300910 (*variable) = new TVariable(&identifier, type);
911 if (!symbolTable.declare(*variable))
912 {
913 error(line, "redefinition", identifier.c_str());
Jamie Madill1a4b1b32015-07-23 18:27:13 -0400914 *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +0300915 return false;
916 }
917
918 if (voidErrorCheck(line, identifier, type.getBasicType()))
919 return false;
920
921 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922}
923
Jamie Madillb98c3a82015-07-23 14:26:04 -0400924bool TParseContext::paramErrorCheck(const TSourceLoc &line,
925 TQualifier qualifier,
926 TQualifier paramQualifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +0530927 TType *type)
928{
929 if (qualifier != EvqConst && qualifier != EvqTemporary)
930 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000931 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000932 return true;
933 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530934 if (qualifier == EvqConst && paramQualifier != EvqIn)
935 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400936 error(line, "qualifier not allowed with ", getQualifierString(qualifier),
937 getQualifierString(paramQualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000938 return true;
939 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000941 if (qualifier == EvqConst)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000942 type->setQualifier(EvqConstReadOnly);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000943 else
alokp@chromium.org58e54292010-08-24 21:40:03 +0000944 type->setQualifier(paramQualifier);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000946 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947}
948
Arun Patole7e7e68d2015-05-22 12:02:25 +0530949bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString &extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000950{
Jamie Madillb98c3a82015-07-23 14:26:04 -0400951 const TExtensionBehavior &extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000952 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
Arun Patole7e7e68d2015-05-22 12:02:25 +0530953 if (iter == extBehavior.end())
954 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000955 error(line, "extension", extension.c_str(), "is not supported");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000956 return true;
957 }
zmo@google.comf5450912011-09-09 01:37:19 +0000958 // In GLSL ES, an extension's default behavior is "disable".
Arun Patole7e7e68d2015-05-22 12:02:25 +0530959 if (iter->second == EBhDisable || iter->second == EBhUndefined)
960 {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000961 error(line, "extension", extension.c_str(), "is disabled");
962 return true;
963 }
Arun Patole7e7e68d2015-05-22 12:02:25 +0530964 if (iter->second == EBhWarn)
965 {
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000966 warning(line, "extension", extension.c_str(), "is being used");
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000967 return false;
968 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000970 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000971}
972
Jamie Madillb98c3a82015-07-23 14:26:04 -0400973// These checks are common for all declarations starting a declarator list, and declarators that
974// follow an empty declaration.
Olli Etuahofa33d582015-04-09 14:33:12 +0300975//
Jamie Madillb98c3a82015-07-23 14:26:04 -0400976bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
977 const TSourceLoc &identifierLocation)
Jamie Madilla5efff92013-06-06 11:56:47 -0400978{
Olli Etuahofa33d582015-04-09 14:33:12 +0300979 switch (publicType.qualifier)
980 {
Jamie Madillb98c3a82015-07-23 14:26:04 -0400981 case EvqVaryingIn:
982 case EvqVaryingOut:
983 case EvqAttribute:
984 case EvqVertexIn:
985 case EvqFragmentOut:
986 if (publicType.type == EbtStruct)
987 {
988 error(identifierLocation, "cannot be used with a structure",
989 getQualifierString(publicType.qualifier));
990 return true;
991 }
Olli Etuahofa33d582015-04-09 14:33:12 +0300992
Jamie Madillb98c3a82015-07-23 14:26:04 -0400993 default:
994 break;
Olli Etuahofa33d582015-04-09 14:33:12 +0300995 }
996
Jamie Madillb98c3a82015-07-23 14:26:04 -0400997 if (publicType.qualifier != EvqUniform &&
998 samplerErrorCheck(identifierLocation, publicType, "samplers must be uniform"))
Olli Etuahofa33d582015-04-09 14:33:12 +0300999 {
Jamie Madilla5efff92013-06-06 11:56:47 -04001000 return true;
Olli Etuahofa33d582015-04-09 14:33:12 +03001001 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001002
1003 // check for layout qualifier issues
1004 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
1005
1006 if (layoutQualifier.matrixPacking != EmpUnspecified)
1007 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001008 error(identifierLocation, "layout qualifier",
1009 getMatrixPackingString(layoutQualifier.matrixPacking),
Olli Etuahofa33d582015-04-09 14:33:12 +03001010 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -04001011 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001012 }
1013
1014 if (layoutQualifier.blockStorage != EbsUnspecified)
1015 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001016 error(identifierLocation, "layout qualifier",
1017 getBlockStorageString(layoutQualifier.blockStorage),
Olli Etuahofa33d582015-04-09 14:33:12 +03001018 "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -04001019 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001020 }
1021
Olli Etuahofa33d582015-04-09 14:33:12 +03001022 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut &&
1023 layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001024 {
Jamie Madill51a53c72013-06-19 09:24:43 -04001025 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -04001026 }
1027
1028 return false;
1029}
1030
Jamie Madillb98c3a82015-07-23 14:26:04 -04001031bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location,
1032 const TLayoutQualifier &layoutQualifier)
Jamie Madilla5efff92013-06-06 11:56:47 -04001033{
1034 if (layoutQualifier.location != -1)
1035 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001036 error(location, "invalid layout qualifier:", "location",
1037 "only valid on program inputs and outputs");
Jamie Madilla5efff92013-06-06 11:56:47 -04001038 return true;
1039 }
1040
1041 return false;
1042}
1043
Jamie Madillb98c3a82015-07-23 14:26:04 -04001044bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
1045 TIntermAggregate *aggregate)
Olli Etuahob6e07a62015-02-16 12:22:10 +02001046{
1047 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
1048 {
1049 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
1050 if (qual == EvqOut || qual == EvqInOut)
1051 {
1052 TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped();
1053 if (lValueErrorCheck(node->getLine(), "assign", node))
1054 {
1055 error(node->getLine(),
Jamie Madillb98c3a82015-07-23 14:26:04 -04001056 "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
Olli Etuahob6e07a62015-02-16 12:22:10 +02001057 recover();
1058 return true;
1059 }
1060 }
1061 }
1062 return false;
1063}
1064
Jamie Madillb98c3a82015-07-23 14:26:04 -04001065void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier,
1066 const TSourceLoc &invariantLocation)
Olli Etuaho37ad4742015-04-27 13:18:50 +03001067{
1068 if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut)
1069 {
1070 error(invariantLocation, "Only out variables can be invariant.", "invariant");
1071 recover();
1072 }
1073}
1074
Arun Patole7e7e68d2015-05-22 12:02:25 +05301075bool TParseContext::supportsExtension(const char *extension)
zmo@google.com09c323a2011-08-12 18:22:25 +00001076{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001077 const TExtensionBehavior &extbehavior = extensionBehavior();
alokp@chromium.org73bc2982012-06-19 18:48:05 +00001078 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
1079 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001080}
1081
Arun Patole7e7e68d2015-05-22 12:02:25 +05301082bool TParseContext::isExtensionEnabled(const char *extension) const
Jamie Madill5d287f52013-07-12 15:38:19 -04001083{
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001084 return ::IsExtensionEnabled(extensionBehavior(), extension);
Jamie Madill5d287f52013-07-12 15:38:19 -04001085}
1086
Jamie Madillb98c3a82015-07-23 14:26:04 -04001087void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
1088 const char *extName,
1089 const char *behavior)
Jamie Madill075edd82013-07-08 13:30:19 -04001090{
1091 pp::SourceLocation srcLoc;
1092 srcLoc.file = loc.first_file;
1093 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001094 mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
Jamie Madill075edd82013-07-08 13:30:19 -04001095}
1096
Jamie Madillb98c3a82015-07-23 14:26:04 -04001097void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
1098 const char *name,
1099 const char *value,
1100 bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -04001101{
1102 pp::SourceLocation srcLoc;
1103 srcLoc.file = loc.first_file;
1104 srcLoc.line = loc.first_line;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001105 mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -04001106}
1107
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001108/////////////////////////////////////////////////////////////////////////////////
1109//
1110// Non-Errors.
1111//
1112/////////////////////////////////////////////////////////////////////////////////
1113
Jamie Madill5c097022014-08-20 16:38:32 -04001114const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1115 const TString *name,
1116 const TSymbol *symbol)
1117{
1118 const TVariable *variable = NULL;
1119
1120 if (!symbol)
1121 {
1122 error(location, "undeclared identifier", name->c_str());
1123 recover();
1124 }
1125 else if (!symbol->isVariable())
1126 {
1127 error(location, "variable expected", name->c_str());
1128 recover();
1129 }
1130 else
1131 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001132 variable = static_cast<const TVariable *>(symbol);
Jamie Madill5c097022014-08-20 16:38:32 -04001133
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001134 if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
Jamie Madill5c097022014-08-20 16:38:32 -04001135 !variable->getExtension().empty() &&
1136 extensionErrorCheck(location, variable->getExtension()))
1137 {
1138 recover();
1139 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001140
1141 // Reject shaders using both gl_FragData and gl_FragColor
1142 TQualifier qualifier = variable->getType().getQualifier();
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001143 if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001144 {
1145 mUsesFragData = true;
1146 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001147 else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
Jamie Madill14e95b32015-05-07 10:10:41 -04001148 {
1149 mUsesFragColor = true;
1150 }
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001151 if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
1152 {
1153 mUsesSecondaryOutputs = true;
1154 }
Jamie Madill14e95b32015-05-07 10:10:41 -04001155
1156 // This validation is not quite correct - it's only an error to write to
1157 // both FragData and FragColor. For simplicity, and because users shouldn't
1158 // be rewarded for reading from undefined varaibles, return an error
1159 // if they are both referenced, rather than assigned.
1160 if (mUsesFragData && mUsesFragColor)
1161 {
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +03001162 const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
1163 if (mUsesSecondaryOutputs)
1164 {
1165 errorMessage =
1166 "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
1167 " and (gl_FragColor, gl_SecondaryFragColorEXT)";
1168 }
1169 error(location, errorMessage, name->c_str());
Jamie Madill14e95b32015-05-07 10:10:41 -04001170 recover();
1171 }
Jamie Madill5c097022014-08-20 16:38:32 -04001172 }
1173
1174 if (!variable)
1175 {
1176 TType type(EbtFloat, EbpUndefined);
1177 TVariable *fakeVariable = new TVariable(name, type);
1178 symbolTable.declare(fakeVariable);
1179 variable = fakeVariable;
1180 }
1181
1182 return variable;
1183}
1184
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185//
1186// Look up a function name in the symbol table, and make sure it is a function.
1187//
1188// Return the function symbol if found, otherwise 0.
1189//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001190const TFunction *TParseContext::findFunction(const TSourceLoc &line,
1191 TFunction *call,
1192 int inputShaderVersion,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301193 bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001194{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001195 // First find by unmangled name to check whether the function name has been
1196 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001197 // If a function is found, check for one with a matching argument list.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301198 const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
1199 if (symbol == 0 || symbol->isFunction())
1200 {
Austin Kinross3ae64652015-01-26 15:51:39 -08001201 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001202 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203
Arun Patole7e7e68d2015-05-22 12:02:25 +05301204 if (symbol == 0)
1205 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001206 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001207 return 0;
1208 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209
Arun Patole7e7e68d2015-05-22 12:02:25 +05301210 if (!symbol->isFunction())
1211 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001212 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001213 return 0;
1214 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001215
Jamie Madillb98c3a82015-07-23 14:26:04 -04001216 return static_cast<const TFunction *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001217}
1218
1219//
1220// Initializers show up in several places in the grammar. Have one set of
1221// code to handle them here.
1222//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001223// Returns true on error, false if no error
1224//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001225bool TParseContext::executeInitializer(const TSourceLoc &line,
1226 const TString &identifier,
1227 const TPublicType &pType,
1228 TIntermTyped *initializer,
1229 TIntermNode **intermNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230{
Olli Etuahoe7847b02015-03-16 11:56:12 +02001231 ASSERT(intermNode != nullptr);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001232 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001233
Olli Etuaho2935c582015-04-08 14:32:06 +03001234 TVariable *variable = nullptr;
Olli Etuaho376f1b52015-04-13 13:23:41 +03001235 if (type.isUnsizedArray())
1236 {
1237 type.setArraySize(initializer->getArraySize());
1238 }
Olli Etuaho2935c582015-04-08 14:32:06 +03001239 if (!declareVariable(line, identifier, type, &variable))
1240 {
1241 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001242 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001243
Olli Etuahob0c645e2015-05-12 14:25:36 +03001244 bool globalInitWarning = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001245 if (symbolTable.atGlobalLevel() &&
1246 !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
Olli Etuahob0c645e2015-05-12 14:25:36 +03001247 {
1248 // Error message does not completely match behavior with ESSL 1.00, but
1249 // we want to steer developers towards only using constant expressions.
1250 error(line, "global variable initializers must be constant expressions", "=");
1251 return true;
1252 }
1253 if (globalInitWarning)
1254 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001255 warning(
1256 line,
1257 "global variable initializers should be constant expressions "
1258 "(uniforms and globals are allowed in global initializers for legacy compatibility)",
1259 "=");
Olli Etuahob0c645e2015-05-12 14:25:36 +03001260 }
1261
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001262 //
1263 // identifier must be of type constant, a global, or a temporary
1264 //
1265 TQualifier qualifier = variable->getType().getQualifier();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301266 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
1267 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001268 error(line, " cannot initialize this type of qualifier ",
1269 variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001270 return true;
1271 }
1272 //
1273 // test for and propagate constant
1274 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001275
Arun Patole7e7e68d2015-05-22 12:02:25 +05301276 if (qualifier == EvqConst)
1277 {
1278 if (qualifier != initializer->getType().getQualifier())
1279 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001280 std::stringstream extraInfoStream;
1281 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1282 std::string extraInfo = extraInfoStream.str();
1283 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001284 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001285 return true;
1286 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301287 if (type != initializer->getType())
1288 {
1289 error(line, " non-matching types for const initializer ",
Jamie Madillb98c3a82015-07-23 14:26:04 -04001290 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001291 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001292 return true;
1293 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301294 if (initializer->getAsConstantUnion())
1295 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001296 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
Arun Patole7e7e68d2015-05-22 12:02:25 +05301297 }
1298 else if (initializer->getAsSymbolNode())
1299 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001300 const TSymbol *symbol =
1301 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1302 const TVariable *tVar = static_cast<const TVariable *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001303
Arun Patole7e7e68d2015-05-22 12:02:25 +05301304 TConstantUnion *constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001305 variable->shareConstPointer(constArray);
Arun Patole7e7e68d2015-05-22 12:02:25 +05301306 }
1307 else
1308 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001309 std::stringstream extraInfoStream;
1310 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1311 std::string extraInfo = extraInfoStream.str();
1312 error(line, " cannot assign to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001313 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001314 return true;
1315 }
1316 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001317
1318 if (qualifier != EvqConst)
1319 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001320 TIntermSymbol *intermSymbol = intermediate.addSymbol(
1321 variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001322 *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
1323 if (*intermNode == nullptr)
1324 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001325 assignError(line, "=", intermSymbol->getCompleteString(),
1326 initializer->getCompleteString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001327 return true;
1328 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001329 }
1330 else
1331 {
1332 *intermNode = nullptr;
1333 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001335 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001336}
1337
Arun Patole7e7e68d2015-05-22 12:02:25 +05301338bool TParseContext::areAllChildConst(TIntermAggregate *aggrNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001339{
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001340 ASSERT(aggrNode != NULL);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001341 if (!aggrNode->isConstructor())
1342 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001343
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001344 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001345
Arun Patole7e7e68d2015-05-22 12:02:25 +05301346 // check if all the child nodes are constants so that they can be inserted into
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001347 // the parent node
Jamie Madillb98c3a82015-07-23 14:26:04 -04001348 TIntermSequence *sequence = aggrNode->getSequence();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301349 for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p)
1350 {
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001351 if (!(*p)->getAsTyped()->getAsConstantUnion())
1352 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001353 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001354
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001355 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001356}
1357
Jamie Madillb98c3a82015-07-23 14:26:04 -04001358TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
1359 bool invariant,
1360 TLayoutQualifier layoutQualifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301361 const TPublicType &typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001362{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001363 TPublicType returnType = typeSpecifier;
1364 returnType.qualifier = qualifier;
1365 returnType.invariant = invariant;
Jamie Madilla5efff92013-06-06 11:56:47 -04001366 returnType.layoutQualifier = layoutQualifier;
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001367
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001368 if (mShaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001369 {
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001370 if (typeSpecifier.array)
1371 {
1372 error(typeSpecifier.line, "not supported", "first-class array");
1373 recover();
1374 returnType.clearArrayness();
1375 }
1376
Jamie Madillb98c3a82015-07-23 14:26:04 -04001377 if (qualifier == EvqAttribute &&
1378 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001379 {
1380 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1381 recover();
1382 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001383
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001384 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1385 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1386 {
1387 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1388 recover();
1389 }
1390 }
1391 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001392 {
Olli Etuahoabb0c382015-07-13 12:01:12 +03001393 if (!layoutQualifier.isEmpty())
1394 {
1395 if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout"))
1396 {
1397 recover();
1398 }
1399 }
Olli Etuahocc36b982015-07-10 14:14:18 +03001400 if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001401 {
Olli Etuahocc36b982015-07-10 14:14:18 +03001402 es3InputOutputTypeCheck(qualifier, typeSpecifier, typeSpecifier.line);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001403 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001404 }
1405
1406 return returnType;
1407}
1408
Olli Etuahocc36b982015-07-10 14:14:18 +03001409void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier,
1410 const TPublicType &type,
1411 const TSourceLoc &qualifierLocation)
1412{
1413 // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
1414 if (type.type == EbtBool)
1415 {
1416 error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
1417 recover();
1418 }
1419
1420 // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
1421 switch (qualifier)
1422 {
1423 case EvqVertexIn:
1424 // ESSL 3.00 section 4.3.4
1425 if (type.array)
1426 {
1427 error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
1428 recover();
1429 }
1430 // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
1431 return;
1432 case EvqFragmentOut:
1433 // ESSL 3.00 section 4.3.6
1434 if (type.isMatrix())
1435 {
1436 error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
1437 recover();
1438 }
1439 // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
1440 return;
1441 default:
1442 break;
1443 }
1444
1445 // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
1446 // restrictions.
1447 bool typeContainsIntegers =
1448 (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) ||
1449 type.isStructureContainingType(EbtUInt));
1450 if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
1451 {
1452 error(qualifierLocation, "must use 'flat' interpolation here",
1453 getQualifierString(qualifier));
1454 recover();
1455 }
1456
1457 if (type.type == EbtStruct)
1458 {
1459 // ESSL 3.00 sections 4.3.4 and 4.3.6.
1460 // These restrictions are only implied by the ESSL 3.00 spec, but
1461 // the ESSL 3.10 spec lists these restrictions explicitly.
1462 if (type.array)
1463 {
1464 error(qualifierLocation, "cannot be an array of structures",
1465 getQualifierString(qualifier));
1466 recover();
1467 }
1468 if (type.isStructureContainingArrays())
1469 {
1470 error(qualifierLocation, "cannot be a structure containing an array",
1471 getQualifierString(qualifier));
1472 recover();
1473 }
1474 if (type.isStructureContainingType(EbtStruct))
1475 {
1476 error(qualifierLocation, "cannot be a structure containing a structure",
1477 getQualifierString(qualifier));
1478 recover();
1479 }
1480 if (type.isStructureContainingType(EbtBool))
1481 {
1482 error(qualifierLocation, "cannot be a structure containing a bool",
1483 getQualifierString(qualifier));
1484 recover();
1485 }
1486 }
1487}
1488
Olli Etuahofa33d582015-04-09 14:33:12 +03001489TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
1490 const TSourceLoc &identifierOrTypeLocation,
1491 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001492{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001493 TIntermSymbol *symbol =
1494 intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001495
Olli Etuahobab4c082015-04-24 16:38:49 +03001496 bool emptyDeclaration = (identifier == "");
Olli Etuahofa33d582015-04-09 14:33:12 +03001497
Olli Etuahobab4c082015-04-24 16:38:49 +03001498 mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
1499
1500 if (emptyDeclaration)
1501 {
1502 if (publicType.isUnsizedArray())
1503 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001504 // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
1505 // error. It is assumed that this applies to empty declarations as well.
1506 error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
1507 identifier.c_str());
Olli Etuahobab4c082015-04-24 16:38:49 +03001508 }
1509 }
1510 else
Jamie Madill60ed9812013-06-06 11:56:46 -04001511 {
Olli Etuahofa33d582015-04-09 14:33:12 +03001512 if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001513 recover();
1514
Olli Etuaho376f1b52015-04-13 13:23:41 +03001515 if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001516 recover();
1517
Olli Etuaho2935c582015-04-08 14:32:06 +03001518 TVariable *variable = nullptr;
Olli Etuahofa33d582015-04-09 14:33:12 +03001519 if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001520 recover();
1521
1522 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001523 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001524 }
1525
Olli Etuahoe7847b02015-03-16 11:56:12 +02001526 return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001527}
1528
Olli Etuahoe7847b02015-03-16 11:56:12 +02001529TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
1530 const TSourceLoc &identifierLocation,
1531 const TString &identifier,
1532 const TSourceLoc &indexLocation,
1533 TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001534{
Olli Etuahofa33d582015-04-09 14:33:12 +03001535 mDeferredSingleDeclarationErrorCheck = false;
1536
1537 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001538 recover();
1539
Olli Etuaho376f1b52015-04-13 13:23:41 +03001540 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001541 recover();
1542
Jamie Madillb98c3a82015-07-23 14:26:04 -04001543 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1544 arrayQualifierErrorCheck(indexLocation, publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001545 {
1546 recover();
1547 }
1548
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001549 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001550
1551 int size;
1552 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1553 {
1554 recover();
1555 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001556 // Make the type an array even if size check failed.
1557 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1558 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001559
Olli Etuaho2935c582015-04-08 14:32:06 +03001560 TVariable *variable = nullptr;
1561 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001562 recover();
1563
Olli Etuahoe7847b02015-03-16 11:56:12 +02001564 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001565 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001566 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001567
Olli Etuahoe7847b02015-03-16 11:56:12 +02001568 return intermediate.makeAggregate(symbol, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001569}
1570
Jamie Madill06145232015-05-13 13:10:01 -04001571TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
Olli Etuahoe7847b02015-03-16 11:56:12 +02001572 const TSourceLoc &identifierLocation,
1573 const TString &identifier,
1574 const TSourceLoc &initLocation,
1575 TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001576{
Olli Etuahofa33d582015-04-09 14:33:12 +03001577 mDeferredSingleDeclarationErrorCheck = false;
1578
1579 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001580 recover();
1581
Olli Etuahoe7847b02015-03-16 11:56:12 +02001582 TIntermNode *intermNode = nullptr;
1583 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill60ed9812013-06-06 11:56:46 -04001584 {
1585 //
1586 // Build intermediate representation
1587 //
Olli Etuahoe7847b02015-03-16 11:56:12 +02001588 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001589 }
1590 else
1591 {
1592 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001593 return nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001594 }
1595}
1596
Jamie Madillb98c3a82015-07-23 14:26:04 -04001597TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
1598 TPublicType &publicType,
1599 const TSourceLoc &identifierLocation,
1600 const TString &identifier,
1601 const TSourceLoc &indexLocation,
1602 TIntermTyped *indexExpression,
1603 const TSourceLoc &initLocation,
1604 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001605{
1606 mDeferredSingleDeclarationErrorCheck = false;
1607
1608 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1609 recover();
1610
Jamie Madillb98c3a82015-07-23 14:26:04 -04001611 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1612 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001613 {
1614 recover();
1615 }
1616
1617 TPublicType arrayType(publicType);
1618
Olli Etuaho376f1b52015-04-13 13:23:41 +03001619 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001620 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1621 // the initializer.
1622 if (indexExpression != nullptr &&
1623 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001624 {
1625 recover();
1626 }
1627 // Make the type an array even if size check failed.
1628 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1629 arrayType.setArraySize(size);
1630
1631 // initNode will correspond to the whole of "type b[n] = initializer".
1632 TIntermNode *initNode = nullptr;
1633 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1634 {
1635 return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
1636 }
1637 else
1638 {
1639 recover();
1640 return nullptr;
1641 }
1642}
1643
Olli Etuahoe7847b02015-03-16 11:56:12 +02001644TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
Jamie Madill47e3ec02014-08-20 16:38:33 -04001645 const TSourceLoc &identifierLoc,
1646 const TString *identifier,
1647 const TSymbol *symbol)
1648{
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001649 // invariant declaration
Jamie Madill47e3ec02014-08-20 16:38:33 -04001650 if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
1651 {
1652 recover();
1653 }
1654
1655 if (!symbol)
1656 {
1657 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
1658 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001659 return nullptr;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001660 }
1661 else
1662 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001663 const TString kGlFrontFacing("gl_FrontFacing");
1664 if (*identifier == kGlFrontFacing)
1665 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001666 error(identifierLoc, "identifier should not be declared as invariant",
1667 identifier->c_str());
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001668 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001669 return nullptr;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001670 }
Jamie Madill2c433252014-12-03 12:36:54 -05001671 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001672 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
1673 ASSERT(variable);
1674 const TType &type = variable->getType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04001675 TIntermSymbol *intermSymbol =
1676 intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001677
1678 TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
1679 aggregate->setOp(EOpInvariantDeclaration);
1680 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001681 }
1682}
1683
Jamie Madillb98c3a82015-07-23 14:26:04 -04001684TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
1685 TIntermAggregate *aggregateDeclaration,
1686 const TSourceLoc &identifierLocation,
1687 const TString &identifier)
Jamie Madill502d66f2013-06-20 11:55:52 -04001688{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001689 // If the declaration starting this declarator list was empty (example: int,), some checks were
1690 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001691 if (mDeferredSingleDeclarationErrorCheck)
1692 {
1693 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1694 recover();
1695 mDeferredSingleDeclarationErrorCheck = false;
1696 }
1697
Jamie Madill0bd18df2013-06-20 11:55:52 -04001698 if (locationDeclaratorListCheck(identifierLocation, publicType))
1699 recover();
1700
Olli Etuaho376f1b52015-04-13 13:23:41 +03001701 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001702 recover();
1703
Olli Etuaho2935c582015-04-08 14:32:06 +03001704 TVariable *variable = nullptr;
1705 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001706 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001707
Jamie Madillb98c3a82015-07-23 14:26:04 -04001708 TIntermSymbol *symbol =
1709 intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001710 if (variable && symbol)
Jamie Madill502d66f2013-06-20 11:55:52 -04001711 symbol->setId(variable->getUniqueId());
1712
Olli Etuahoe7847b02015-03-16 11:56:12 +02001713 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001714}
1715
Jamie Madillb98c3a82015-07-23 14:26:04 -04001716TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
1717 TIntermAggregate *aggregateDeclaration,
1718 const TSourceLoc &identifierLocation,
1719 const TString &identifier,
1720 const TSourceLoc &arrayLocation,
1721 TIntermTyped *indexExpression)
Jamie Madill502d66f2013-06-20 11:55:52 -04001722{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001723 // If the declaration starting this declarator list was empty (example: int,), some checks were
1724 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001725 if (mDeferredSingleDeclarationErrorCheck)
1726 {
1727 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1728 recover();
1729 mDeferredSingleDeclarationErrorCheck = false;
1730 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001731
Jamie Madill0bd18df2013-06-20 11:55:52 -04001732 if (locationDeclaratorListCheck(identifierLocation, publicType))
1733 recover();
1734
Olli Etuaho376f1b52015-04-13 13:23:41 +03001735 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001736 recover();
1737
Jamie Madillb98c3a82015-07-23 14:26:04 -04001738 if (arrayTypeErrorCheck(arrayLocation, publicType) ||
1739 arrayQualifierErrorCheck(arrayLocation, publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001740 {
1741 recover();
1742 }
Olli Etuaho93a90fd2015-04-07 18:14:07 +03001743 else
Jamie Madill502d66f2013-06-20 11:55:52 -04001744 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001745 TType arrayType = TType(publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04001746 int size;
1747 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
Olli Etuahoe7847b02015-03-16 11:56:12 +02001748 {
Jamie Madill502d66f2013-06-20 11:55:52 -04001749 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001750 }
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001751 arrayType.setArraySize(size);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001752
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001753 TVariable *variable = nullptr;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001754 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001755 recover();
Jamie Madill502d66f2013-06-20 11:55:52 -04001756
Jamie Madillb98c3a82015-07-23 14:26:04 -04001757 TIntermSymbol *symbol =
1758 intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001759 if (variable && symbol)
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001760 symbol->setId(variable->getUniqueId());
Olli Etuahoe7847b02015-03-16 11:56:12 +02001761
1762 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001763 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001764
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001765 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001766}
1767
Jamie Madillb98c3a82015-07-23 14:26:04 -04001768TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
1769 TIntermAggregate *aggregateDeclaration,
1770 const TSourceLoc &identifierLocation,
1771 const TString &identifier,
1772 const TSourceLoc &initLocation,
1773 TIntermTyped *initializer)
Jamie Madill502d66f2013-06-20 11:55:52 -04001774{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001775 // If the declaration starting this declarator list was empty (example: int,), some checks were
1776 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001777 if (mDeferredSingleDeclarationErrorCheck)
1778 {
1779 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1780 recover();
1781 mDeferredSingleDeclarationErrorCheck = false;
1782 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001783
Jamie Madill0bd18df2013-06-20 11:55:52 -04001784 if (locationDeclaratorListCheck(identifierLocation, publicType))
1785 recover();
1786
Olli Etuahoe7847b02015-03-16 11:56:12 +02001787 TIntermNode *intermNode = nullptr;
1788 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill502d66f2013-06-20 11:55:52 -04001789 {
1790 //
1791 // build the intermediate representation
1792 //
1793 if (intermNode)
1794 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001795 return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001796 }
1797 else
1798 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001799 return aggregateDeclaration;
Jamie Madill502d66f2013-06-20 11:55:52 -04001800 }
1801 }
1802 else
1803 {
1804 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001805 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001806 }
1807}
1808
Jamie Madill06145232015-05-13 13:10:01 -04001809TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001810 TIntermAggregate *aggregateDeclaration,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301811 const TSourceLoc &identifierLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001812 const TString &identifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301813 const TSourceLoc &indexLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001814 TIntermTyped *indexExpression,
Jamie Madillb98c3a82015-07-23 14:26:04 -04001815 const TSourceLoc &initLocation,
1816 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001817{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001818 // If the declaration starting this declarator list was empty (example: int,), some checks were
1819 // not performed.
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001820 if (mDeferredSingleDeclarationErrorCheck)
1821 {
1822 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1823 recover();
1824 mDeferredSingleDeclarationErrorCheck = false;
1825 }
1826
1827 if (locationDeclaratorListCheck(identifierLocation, publicType))
1828 recover();
1829
Jamie Madillb98c3a82015-07-23 14:26:04 -04001830 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1831 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001832 {
1833 recover();
1834 }
1835
1836 TPublicType arrayType(publicType);
1837
Olli Etuaho376f1b52015-04-13 13:23:41 +03001838 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001839 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1840 // the initializer.
1841 if (indexExpression != nullptr &&
1842 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001843 {
1844 recover();
1845 }
1846 // Make the type an array even if size check failed.
1847 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1848 arrayType.setArraySize(size);
1849
1850 // initNode will correspond to the whole of "b[n] = initializer".
1851 TIntermNode *initNode = nullptr;
1852 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1853 {
1854 if (initNode)
1855 {
1856 return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
1857 }
1858 else
1859 {
1860 return aggregateDeclaration;
1861 }
1862 }
1863 else
1864 {
1865 recover();
1866 return nullptr;
1867 }
1868}
1869
Jamie Madilla295edf2013-06-06 11:56:48 -04001870void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1871{
1872 if (typeQualifier.qualifier != EvqUniform)
1873 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001874 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
1875 "global layout must be uniform");
Jamie Madilla295edf2013-06-06 11:56:48 -04001876 recover();
1877 return;
1878 }
1879
1880 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1881 ASSERT(!layoutQualifier.isEmpty());
1882
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001883 if (mShaderVersion < 300)
Jamie Madilla295edf2013-06-06 11:56:48 -04001884 {
1885 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1886 recover();
1887 return;
1888 }
1889
1890 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1891 {
1892 recover();
1893 return;
1894 }
1895
Jamie Madill099c0f32013-06-20 11:55:52 -04001896 if (layoutQualifier.matrixPacking != EmpUnspecified)
1897 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001898 mDefaultMatrixPacking = layoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04001899 }
1900
Geoff Langc6856732014-02-11 09:38:55 -05001901 if (layoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001902 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001903 mDefaultBlockStorage = layoutQualifier.blockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04001904 }
Jamie Madilla295edf2013-06-06 11:56:48 -04001905}
1906
Jamie Madill185fb402015-06-12 15:48:48 -04001907void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
1908 TFunction *function,
1909 TIntermAggregate **aggregateOut)
1910{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001911 const TSymbol *builtIn =
1912 symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04001913
1914 if (builtIn)
1915 {
1916 error(location, "built-in functions cannot be redefined", function->getName().c_str());
1917 recover();
1918 }
1919
Jamie Madillb98c3a82015-07-23 14:26:04 -04001920 TFunction *prevDec =
1921 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
Jamie Madill185fb402015-06-12 15:48:48 -04001922 //
1923 // Note: 'prevDec' could be 'function' if this is the first time we've seen function
1924 // as it would have just been put in the symbol table. Otherwise, we're looking up
1925 // an earlier occurance.
1926 //
1927 if (prevDec->isDefined())
1928 {
1929 // Then this function already has a body.
1930 error(location, "function already has a body", function->getName().c_str());
1931 recover();
1932 }
1933 prevDec->setDefined();
1934 //
1935 // Overload the unique ID of the definition to be the same unique ID as the declaration.
1936 // Eventually we will probably want to have only a single definition and just swap the
1937 // arguments to be the definition's arguments.
1938 //
1939 function->setUniqueId(prevDec->getUniqueId());
1940
1941 // Raise error message if main function takes any parameters or return anything other than void
1942 if (function->getName() == "main")
1943 {
1944 if (function->getParamCount() > 0)
1945 {
1946 error(location, "function cannot take any parameter(s)", function->getName().c_str());
1947 recover();
1948 }
1949 if (function->getReturnType().getBasicType() != EbtVoid)
1950 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001951 error(location, "", function->getReturnType().getBasicString(),
1952 "main function cannot return a value");
Jamie Madill185fb402015-06-12 15:48:48 -04001953 recover();
1954 }
1955 }
1956
1957 //
1958 // Remember the return type for later checking for RETURN statements.
1959 //
1960 setCurrentFunctionType(&(prevDec->getReturnType()));
1961 setFunctionReturnsValue(false);
1962
1963 //
1964 // Insert parameters into the symbol table.
1965 // If the parameter has no name, it's not an error, just don't insert it
1966 // (could be used for unused args).
1967 //
1968 // Also, accumulate the list of parameters into the HIL, so lower level code
1969 // knows where to find parameters.
1970 //
1971 TIntermAggregate *paramNodes = new TIntermAggregate;
1972 for (size_t i = 0; i < function->getParamCount(); i++)
1973 {
1974 const TConstParameter &param = function->getParam(i);
1975 if (param.name != 0)
1976 {
1977 TVariable *variable = new TVariable(param.name, *param.type);
1978 //
1979 // Insert the parameters with name in the symbol table.
1980 //
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001981 if (!symbolTable.declare(variable))
1982 {
Jamie Madill185fb402015-06-12 15:48:48 -04001983 error(location, "redefinition", variable->getName().c_str());
1984 recover();
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001985 paramNodes = intermediate.growAggregate(
1986 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
1987 continue;
Jamie Madill185fb402015-06-12 15:48:48 -04001988 }
1989
1990 //
1991 // Add the parameter to the HIL
1992 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04001993 TIntermSymbol *symbol = intermediate.addSymbol(
1994 variable->getUniqueId(), variable->getName(), variable->getType(), location);
Jamie Madill185fb402015-06-12 15:48:48 -04001995
1996 paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
1997 }
1998 else
1999 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002000 paramNodes = intermediate.growAggregate(
2001 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002002 }
2003 }
2004 intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
2005 *aggregateOut = paramNodes;
2006 setLoopNestingLevel(0);
2007}
2008
Jamie Madillb98c3a82015-07-23 14:26:04 -04002009TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
Jamie Madill185fb402015-06-12 15:48:48 -04002010{
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002011 //
2012 // Multiple declarations of the same function are allowed.
2013 //
2014 // If this is a definition, the definition production code will check for redefinitions
2015 // (we don't know at this point if it's a definition or not).
2016 //
2017 // Redeclarations are allowed. But, return types and parameter qualifiers must match.
2018 //
2019 TFunction *prevDec =
2020 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
2021 if (prevDec)
Jamie Madill185fb402015-06-12 15:48:48 -04002022 {
2023 if (prevDec->getReturnType() != function->getReturnType())
2024 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002025 error(location, "overloaded functions must have the same return type",
Jamie Madill185fb402015-06-12 15:48:48 -04002026 function->getReturnType().getBasicString());
2027 recover();
2028 }
2029 for (size_t i = 0; i < prevDec->getParamCount(); ++i)
2030 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002031 if (prevDec->getParam(i).type->getQualifier() !=
2032 function->getParam(i).type->getQualifier())
Jamie Madill185fb402015-06-12 15:48:48 -04002033 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002034 error(location, "overloaded functions must have the same parameter qualifiers",
Jamie Madill185fb402015-06-12 15:48:48 -04002035 function->getParam(i).type->getQualifierString());
2036 recover();
2037 }
2038 }
2039 }
2040
2041 //
2042 // Check for previously declared variables using the same name.
2043 //
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002044 TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002045 if (prevSym)
2046 {
2047 if (!prevSym->isFunction())
2048 {
2049 error(location, "redefinition", function->getName().c_str(), "function");
2050 recover();
2051 }
2052 }
2053 else
2054 {
2055 // Insert the unmangled name to detect potential future redefinition as a variable.
Jamie Madillb98c3a82015-07-23 14:26:04 -04002056 TFunction *newFunction =
2057 new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
Jamie Madill185fb402015-06-12 15:48:48 -04002058 symbolTable.getOuterLevel()->insertUnmangled(newFunction);
2059 }
2060
2061 // We're at the inner scope level of the function's arguments and body statement.
2062 // Add the function prototype to the surrounding scope instead.
2063 symbolTable.getOuterLevel()->insert(function);
2064
2065 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002066 // If this is a redeclaration, it could also be a definition, in which case, we want to use the
2067 // variable names from this one, and not the one that's
Jamie Madill185fb402015-06-12 15:48:48 -04002068 // being redeclared. So, pass back up this declaration, not the one in the symbol table.
2069 //
2070 return function;
2071}
2072
Jamie Madill06145232015-05-13 13:10:01 -04002073TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002074{
Jamie Madill06145232015-05-13 13:10:01 -04002075 TPublicType publicType = publicTypeIn;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002076 TOperator op = EOpNull;
2077 if (publicType.userDef)
2078 {
2079 op = EOpConstructStruct;
2080 }
2081 else
2082 {
2083 switch (publicType.type)
2084 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002085 case EbtFloat:
2086 if (publicType.isMatrix())
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002087 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002088 switch (publicType.getCols())
Alexis Hetu07e57df2015-06-16 16:55:52 -04002089 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002090 case 2:
2091 switch (publicType.getRows())
2092 {
2093 case 2:
2094 op = EOpConstructMat2;
2095 break;
2096 case 3:
2097 op = EOpConstructMat2x3;
2098 break;
2099 case 4:
2100 op = EOpConstructMat2x4;
2101 break;
2102 }
2103 break;
2104 case 3:
2105 switch (publicType.getRows())
2106 {
2107 case 2:
2108 op = EOpConstructMat3x2;
2109 break;
2110 case 3:
2111 op = EOpConstructMat3;
2112 break;
2113 case 4:
2114 op = EOpConstructMat3x4;
2115 break;
2116 }
2117 break;
2118 case 4:
2119 switch (publicType.getRows())
2120 {
2121 case 2:
2122 op = EOpConstructMat4x2;
2123 break;
2124 case 3:
2125 op = EOpConstructMat4x3;
2126 break;
2127 case 4:
2128 op = EOpConstructMat4;
2129 break;
2130 }
2131 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -04002132 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002133 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002134 else
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002135 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002136 switch (publicType.getNominalSize())
2137 {
2138 case 1:
2139 op = EOpConstructFloat;
2140 break;
2141 case 2:
2142 op = EOpConstructVec2;
2143 break;
2144 case 3:
2145 op = EOpConstructVec3;
2146 break;
2147 case 4:
2148 op = EOpConstructVec4;
2149 break;
2150 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002151 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002152 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002153
Jamie Madillb98c3a82015-07-23 14:26:04 -04002154 case EbtInt:
2155 switch (publicType.getNominalSize())
2156 {
2157 case 1:
2158 op = EOpConstructInt;
2159 break;
2160 case 2:
2161 op = EOpConstructIVec2;
2162 break;
2163 case 3:
2164 op = EOpConstructIVec3;
2165 break;
2166 case 4:
2167 op = EOpConstructIVec4;
2168 break;
2169 }
2170 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002171
Jamie Madillb98c3a82015-07-23 14:26:04 -04002172 case EbtUInt:
2173 switch (publicType.getNominalSize())
2174 {
2175 case 1:
2176 op = EOpConstructUInt;
2177 break;
2178 case 2:
2179 op = EOpConstructUVec2;
2180 break;
2181 case 3:
2182 op = EOpConstructUVec3;
2183 break;
2184 case 4:
2185 op = EOpConstructUVec4;
2186 break;
2187 }
2188 break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002189
Jamie Madillb98c3a82015-07-23 14:26:04 -04002190 case EbtBool:
2191 switch (publicType.getNominalSize())
2192 {
2193 case 1:
2194 op = EOpConstructBool;
2195 break;
2196 case 2:
2197 op = EOpConstructBVec2;
2198 break;
2199 case 3:
2200 op = EOpConstructBVec3;
2201 break;
2202 case 4:
2203 op = EOpConstructBVec4;
2204 break;
2205 }
2206 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002207
Jamie Madillb98c3a82015-07-23 14:26:04 -04002208 default:
2209 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002210 }
2211
2212 if (op == EOpNull)
2213 {
2214 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
2215 recover();
2216 publicType.type = EbtFloat;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002217 op = EOpConstructFloat;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002218 }
2219 }
2220
2221 TString tempString;
Dmitry Skiba7f17a502015-06-22 15:08:39 -07002222 const TType *type = new TType(publicType);
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002223 return new TFunction(&tempString, type, op);
2224}
2225
Jamie Madillb98c3a82015-07-23 14:26:04 -04002226// This function is used to test for the correctness of the parameters passed to various constructor
2227// functions and also convert them to the right datatype if it is allowed and required.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002228//
2229// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
2230//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002231TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
2232 TType *type,
2233 TOperator op,
2234 TFunction *fnCall,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302235 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002236{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002237 TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002238
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002239 if (!aggregateArguments)
2240 {
2241 aggregateArguments = new TIntermAggregate;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002242 aggregateArguments->getSequence()->push_back(arguments);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002243 }
2244
Olli Etuahof40319e2015-03-10 14:33:00 +02002245 if (type->isArray())
2246 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002247 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
2248 // the array.
Olli Etuahof40319e2015-03-10 14:33:00 +02002249 TIntermSequence *args = aggregateArguments->getSequence();
2250 for (size_t i = 0; i < args->size(); i++)
2251 {
2252 const TType &argType = (*args)[i]->getAsTyped()->getType();
2253 // It has already been checked that the argument is not an array.
2254 ASSERT(!argType.isArray());
2255 if (!argType.sameElementType(*type))
2256 {
2257 error(line, "Array constructor argument has an incorrect type", "Error");
2258 recover();
2259 return nullptr;
2260 }
2261 }
2262 }
2263 else if (op == EOpConstructStruct)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002264 {
2265 const TFieldList &fields = type->getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002266 TIntermSequence *args = aggregateArguments->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002267
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002268 for (size_t i = 0; i < fields.size(); i++)
2269 {
Nicolas Capensffd73872014-08-21 13:49:16 -04002270 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002271 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002272 error(line, "Structure constructor arguments do not match structure fields",
2273 "Error");
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002274 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002275
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002276 return 0;
2277 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002278 }
2279 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002280
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002281 // Turn the argument list itself into a constructor
Jamie Madillb98c3a82015-07-23 14:26:04 -04002282 TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
Olli Etuaho21203702014-11-13 16:16:21 +02002283 TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002284 if (constConstructor)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002285 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002286 return constConstructor;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002287 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002288
Olli Etuaho21203702014-11-13 16:16:21 +02002289 // Structs should not be precision qualified, the individual members may be.
2290 // Built-in types on the other hand should be precision qualified.
2291 if (op != EOpConstructStruct)
2292 {
2293 constructor->setPrecisionFromChildren();
2294 type->setPrecision(constructor->getPrecision());
2295 }
2296
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002297 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002298}
2299
Arun Patole7e7e68d2015-05-22 12:02:25 +05302300TIntermTyped *TParseContext::foldConstConstructor(TIntermAggregate *aggrNode, const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002301{
Olli Etuahof40319e2015-03-10 14:33:00 +02002302 // TODO: Add support for folding array constructors
2303 bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002304 aggrNode->setType(type);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302305 if (canBeFolded)
2306 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002307 bool returnVal = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302308 TConstantUnion *unionArray = new TConstantUnion[type.getObjectSize()];
2309 if (aggrNode->getSequence()->size() == 1)
2310 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002311 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2312 aggrNode->getOp(), type, true);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002313 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302314 else
2315 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002316 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2317 aggrNode->getOp(), type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002318 }
2319 if (returnVal)
2320 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002321
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002322 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
2323 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002324
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002325 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002326}
2327
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002328//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002329// This function returns the tree representation for the vector field(s) being accessed from contant
2330// vector.
2331// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a
2332// contant node is returned, else an aggregate node is returned (for v.xy). The input to this
2333// function could either
2334// be the symbol node or it could be the intermediate tree representation of accessing fields in a
2335// constant
2336// structure or column of a constant matrix.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002337//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002338TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields,
2339 TIntermTyped *node,
2340 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002341{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302342 TIntermTyped *typedNode;
2343 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002344
Jamie Madillb11e2482015-05-04 14:21:22 -04002345 const TConstantUnion *unionArray;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302346 if (tempConstantNode)
2347 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002348 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002349
Arun Patole7e7e68d2015-05-22 12:02:25 +05302350 if (!unionArray)
2351 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002352 return node;
2353 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302354 }
2355 else
Jamie Madillb98c3a82015-07-23 14:26:04 -04002356 { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else,
2357 // its an error
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002358 error(line, "Cannot offset into the vector", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002359 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002360
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002361 return 0;
2362 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002363
Arun Patole7e7e68d2015-05-22 12:02:25 +05302364 TConstantUnion *constArray = new TConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002365
Arun Patole7e7e68d2015-05-22 12:02:25 +05302366 for (int i = 0; i < fields.num; i++)
2367 {
2368 if (fields.offsets[i] >= node->getType().getNominalSize())
2369 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002370 std::stringstream extraInfoStream;
2371 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
2372 std::string extraInfo = extraInfoStream.str();
2373 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002374 recover();
2375 fields.offsets[i] = 0;
2376 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302377
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002378 constArray[i] = unionArray[fields.offsets[i]];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302379 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002380 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
2381 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002382}
2383
2384//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002385// This function returns the column being accessed from a constant matrix. The values are retrieved
2386// from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector).
2387// The
2388// input to the function could either be a symbol node (m[0] where m is a constant matrix)that
2389// represents
2390// a constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s
2391// is a constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002392//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002393TIntermTyped *TParseContext::addConstMatrixNode(int index,
2394 TIntermTyped *node,
2395 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002396{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302397 TIntermTyped *typedNode;
2398 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002399
Arun Patole7e7e68d2015-05-22 12:02:25 +05302400 if (index >= node->getType().getCols())
2401 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002402 std::stringstream extraInfoStream;
2403 extraInfoStream << "matrix field selection out of range '" << index << "'";
2404 std::string extraInfo = extraInfoStream.str();
2405 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002406 recover();
2407 index = 0;
2408 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002409
Arun Patole7e7e68d2015-05-22 12:02:25 +05302410 if (tempConstantNode)
2411 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002412 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
2413 int size = tempConstantNode->getType().getCols();
2414 typedNode = intermediate.addConstantUnion(&unionArray[size * index],
2415 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302416 }
2417 else
2418 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002419 error(line, "Cannot offset into the matrix", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002420 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002421
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002422 return 0;
2423 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002424
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002425 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002426}
2427
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002428//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002429// This function returns an element of an array accessed from a constant array. The values are
2430// 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 +05302431// 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 -04002432// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a
2433// constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002434//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002435TIntermTyped *TParseContext::addConstArrayNode(int index,
2436 TIntermTyped *node,
2437 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002438{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302439 TIntermTyped *typedNode;
2440 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002441 TType arrayElementType = node->getType();
2442 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002443
Arun Patole7e7e68d2015-05-22 12:02:25 +05302444 if (index >= node->getType().getArraySize())
2445 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002446 std::stringstream extraInfoStream;
2447 extraInfoStream << "array field selection out of range '" << index << "'";
2448 std::string extraInfo = extraInfoStream.str();
2449 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002450 recover();
2451 index = 0;
2452 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002453
Arun Patole7e7e68d2015-05-22 12:02:25 +05302454 if (tempConstantNode)
2455 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002456 size_t arrayElementSize = arrayElementType.getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302457 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002458 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index],
2459 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302460 }
2461 else
2462 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002463 error(line, "Cannot offset into the array", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002464 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002465
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002466 return 0;
2467 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002468
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002469 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002470}
2471
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002472//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002473// This function returns the value of a particular field inside a constant structure from the symbol
2474// table.
2475// If there is an embedded/nested struct, it appropriately calls addConstStructNested or
2476// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
2477// struct.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002478//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002479TIntermTyped *TParseContext::addConstStruct(const TString &identifier,
2480 TIntermTyped *node,
2481 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002482{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302483 const TFieldList &fields = node->getType().getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002484 size_t instanceSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002485
Arun Patole7e7e68d2015-05-22 12:02:25 +05302486 for (size_t index = 0; index < fields.size(); ++index)
2487 {
2488 if (fields[index]->name() == identifier)
2489 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002490 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302491 }
2492 else
2493 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002494 instanceSize += fields[index]->type()->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002495 }
2496 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002497
Jamie Madill94bf7f22013-07-08 13:31:15 -04002498 TIntermTyped *typedNode;
2499 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302500 if (tempConstantNode)
2501 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002502 TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002503
Jamie Madillb98c3a82015-07-23 14:26:04 -04002504 // type will be changed in the calling function
2505 typedNode = intermediate.addConstantUnion(constArray + instanceSize,
2506 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302507 }
2508 else
2509 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002510 error(line, "Cannot offset into the structure", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002511 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002512
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002513 return 0;
2514 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002515
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002516 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002517}
2518
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002519//
2520// Interface/uniform blocks
2521//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002522TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualifier,
2523 const TSourceLoc &nameLine,
2524 const TString &blockName,
2525 TFieldList *fieldList,
2526 const TString *instanceName,
2527 const TSourceLoc &instanceLine,
2528 TIntermTyped *arrayIndex,
2529 const TSourceLoc &arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002530{
2531 if (reservedErrorCheck(nameLine, blockName))
2532 recover();
2533
2534 if (typeQualifier.qualifier != EvqUniform)
2535 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302536 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
2537 "interface blocks must be uniform");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002538 recover();
2539 }
2540
Jamie Madill099c0f32013-06-20 11:55:52 -04002541 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
2542 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002543 {
2544 recover();
2545 }
2546
Jamie Madill099c0f32013-06-20 11:55:52 -04002547 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
2548 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002549 blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002550 }
2551
Jamie Madill1566ef72013-06-20 11:55:54 -04002552 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
2553 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002554 blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04002555 }
2556
Arun Patole7e7e68d2015-05-22 12:02:25 +05302557 TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
2558 if (!symbolTable.declare(blockNameSymbol))
2559 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002560 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
2561 recover();
2562 }
2563
Jamie Madill98493dd2013-07-08 14:39:03 -04002564 // check for sampler types and apply layout qualifiers
Arun Patole7e7e68d2015-05-22 12:02:25 +05302565 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2566 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002567 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302568 TType *fieldType = field->type();
2569 if (IsSampler(fieldType->getBasicType()))
2570 {
2571 error(field->line(), "unsupported type", fieldType->getBasicString(),
2572 "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002573 recover();
2574 }
2575
Jamie Madill98493dd2013-07-08 14:39:03 -04002576 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002577 switch (qualifier)
2578 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002579 case EvqGlobal:
2580 case EvqUniform:
2581 break;
2582 default:
2583 error(field->line(), "invalid qualifier on interface block member",
2584 getQualifierString(qualifier));
2585 recover();
2586 break;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002587 }
Jamie Madilla5efff92013-06-06 11:56:47 -04002588
2589 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04002590 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
2591 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002592 {
2593 recover();
2594 }
Jamie Madill099c0f32013-06-20 11:55:52 -04002595
Jamie Madill98493dd2013-07-08 14:39:03 -04002596 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04002597 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002598 error(field->line(), "invalid layout qualifier:",
2599 getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04002600 recover();
2601 }
2602
Jamie Madill98493dd2013-07-08 14:39:03 -04002603 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04002604 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002605 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002606 }
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002607 else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
Jamie Madill099c0f32013-06-20 11:55:52 -04002608 {
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002609 warning(field->line(), "extraneous layout qualifier:",
Jamie Madillb98c3a82015-07-23 14:26:04 -04002610 getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
2611 "only has an effect on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04002612 }
2613
Jamie Madill98493dd2013-07-08 14:39:03 -04002614 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002615 }
2616
Jamie Madill98493dd2013-07-08 14:39:03 -04002617 // add array index
2618 int arraySize = 0;
2619 if (arrayIndex != NULL)
2620 {
2621 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
2622 recover();
2623 }
2624
Jamie Madillb98c3a82015-07-23 14:26:04 -04002625 TInterfaceBlock *interfaceBlock =
2626 new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
2627 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
2628 arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002629
2630 TString symbolName = "";
Jamie Madillb98c3a82015-07-23 14:26:04 -04002631 int symbolId = 0;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002632
Jamie Madill98493dd2013-07-08 14:39:03 -04002633 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002634 {
2635 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04002636 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2637 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002638 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302639 TType *fieldType = field->type();
Jamie Madill98493dd2013-07-08 14:39:03 -04002640
2641 // set parent pointer of the field variable
2642 fieldType->setInterfaceBlock(interfaceBlock);
2643
Arun Patole7e7e68d2015-05-22 12:02:25 +05302644 TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -04002645 fieldVariable->setQualifier(typeQualifier.qualifier);
2646
Arun Patole7e7e68d2015-05-22 12:02:25 +05302647 if (!symbolTable.declare(fieldVariable))
2648 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002649 error(field->line(), "redefinition", field->name().c_str(),
2650 "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002651 recover();
2652 }
2653 }
2654 }
2655 else
2656 {
Olli Etuahoe0f623a2015-07-10 11:58:30 +03002657 if (reservedErrorCheck(instanceLine, *instanceName))
2658 recover();
2659
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002660 // add a symbol for this interface block
Arun Patole7e7e68d2015-05-22 12:02:25 +05302661 TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002662 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04002663
Arun Patole7e7e68d2015-05-22 12:02:25 +05302664 if (!symbolTable.declare(instanceTypeDef))
2665 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002666 error(instanceLine, "redefinition", instanceName->c_str(),
2667 "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002668 recover();
2669 }
2670
Jamie Madillb98c3a82015-07-23 14:26:04 -04002671 symbolId = instanceTypeDef->getUniqueId();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002672 symbolName = instanceTypeDef->getName();
2673 }
2674
Jamie Madillb98c3a82015-07-23 14:26:04 -04002675 TIntermAggregate *aggregate = intermediate.makeAggregate(
2676 intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
2677 nameLine);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002678 aggregate->setOp(EOpDeclaration);
Jamie Madill98493dd2013-07-08 14:39:03 -04002679
2680 exitStructDeclaration();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002681 return aggregate;
2682}
2683
Arun Patole7e7e68d2015-05-22 12:02:25 +05302684bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002685{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002686 ++mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002687
2688 // Embedded structure definitions are not supported per GLSL ES spec.
2689 // They aren't allowed in GLSL either, but we need to detect this here
2690 // so we don't rely on the GLSL compiler to catch it.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302691 if (mStructNestingLevel > 1)
2692 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002693 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002694 return true;
2695 }
2696
2697 return false;
2698}
2699
2700void TParseContext::exitStructDeclaration()
2701{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002702 --mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002703}
2704
Jamie Madillb98c3a82015-07-23 14:26:04 -04002705namespace
2706{
kbr@chromium.org476541f2011-10-27 21:14:51 +00002707const int kWebGLMaxStructNesting = 4;
2708
2709} // namespace
2710
Arun Patole7e7e68d2015-05-22 12:02:25 +05302711bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002712{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302713 if (!IsWebGLBasedSpec(mShaderSpec))
2714 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002715 return false;
2716 }
2717
Arun Patole7e7e68d2015-05-22 12:02:25 +05302718 if (field.type()->getBasicType() != EbtStruct)
2719 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002720 return false;
2721 }
2722
2723 // We're already inside a structure definition at this point, so add
2724 // one to the field's struct nesting.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302725 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
2726 {
Jamie Madill41a49272014-03-18 16:10:13 -04002727 std::stringstream reasonStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002728 reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
2729 << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
Jamie Madill41a49272014-03-18 16:10:13 -04002730 std::string reason = reasonStream.str();
2731 error(line, reason.c_str(), field.name().c_str(), "");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002732 return true;
2733 }
2734
2735 return false;
2736}
2737
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00002738//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002739// Parse an array index expression
2740//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002741TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
2742 const TSourceLoc &location,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302743 TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002744{
2745 TIntermTyped *indexedExpression = NULL;
2746
2747 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2748 {
2749 if (baseExpression->getAsSymbolNode())
2750 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302751 error(location, " left of '[' is not of type array, matrix, or vector ",
2752 baseExpression->getAsSymbolNode()->getSymbol().c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002753 }
2754 else
2755 {
2756 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2757 }
2758 recover();
2759 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002760
Jamie Madill21c1e452014-12-29 11:33:41 -05002761 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2762
2763 if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04002764 {
Jamie Madill21c1e452014-12-29 11:33:41 -05002765 int index = indexConstantUnion->getIConst(0);
Jamie Madill7164cf42013-07-08 13:30:59 -04002766 if (index < 0)
2767 {
2768 std::stringstream infoStream;
2769 infoStream << index;
2770 std::string info = infoStream.str();
2771 error(location, "negative index", info.c_str());
2772 recover();
2773 index = 0;
2774 }
2775 if (baseExpression->getType().getQualifier() == EvqConst)
2776 {
2777 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002778 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002779 // constant folding for arrays
2780 indexedExpression = addConstArrayNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002781 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002782 else if (baseExpression->isVector())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002783 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002784 // constant folding for vectors
2785 TVectorFields fields;
2786 fields.num = 1;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002787 fields.offsets[0] =
2788 index; // need to do it this way because v.xy sends fields integer array
Jamie Madill7164cf42013-07-08 13:30:59 -04002789 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2790 }
2791 else if (baseExpression->isMatrix())
2792 {
2793 // constant folding for matrices
2794 indexedExpression = addConstMatrixNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002795 }
2796 }
2797 else
2798 {
Jamie Madillb11e2482015-05-04 14:21:22 -04002799 int safeIndex = -1;
2800
Jamie Madill7164cf42013-07-08 13:30:59 -04002801 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002802 {
Jamie Madill18464b52013-07-08 14:01:55 -04002803 if (index >= baseExpression->getType().getArraySize())
Jamie Madill7164cf42013-07-08 13:30:59 -04002804 {
2805 std::stringstream extraInfoStream;
2806 extraInfoStream << "array index out of range '" << index << "'";
2807 std::string extraInfo = extraInfoStream.str();
2808 error(location, "", "[", extraInfo.c_str());
2809 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002810 safeIndex = baseExpression->getType().getArraySize() - 1;
Jamie Madill7164cf42013-07-08 13:30:59 -04002811 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302812 else if (baseExpression->getQualifier() == EvqFragData && index > 0 &&
2813 !isExtensionEnabled("GL_EXT_draw_buffers"))
Jamie Madill5d287f52013-07-12 15:38:19 -04002814 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002815 error(location, "", "[",
2816 "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is "
2817 "disabled");
Jamie Madill5d287f52013-07-12 15:38:19 -04002818 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002819 safeIndex = 0;
Jamie Madill5d287f52013-07-12 15:38:19 -04002820 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002821 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302822 else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
Jamie Madillb98c3a82015-07-23 14:26:04 -04002823 baseExpression->getType().getNominalSize() <= index)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002824 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002825 std::stringstream extraInfoStream;
2826 extraInfoStream << "field selection out of range '" << index << "'";
2827 std::string extraInfo = extraInfoStream.str();
2828 error(location, "", "[", extraInfo.c_str());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002829 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002830 safeIndex = baseExpression->getType().getNominalSize() - 1;
Jamie Madill46131a32013-06-20 11:55:50 -04002831 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002832
Jamie Madillb11e2482015-05-04 14:21:22 -04002833 // Don't modify the data of the previous constant union, because it can point
2834 // to builtins, like gl_MaxDrawBuffers. Instead use a new sanitized object.
2835 if (safeIndex != -1)
2836 {
2837 TConstantUnion *safeConstantUnion = new TConstantUnion();
2838 safeConstantUnion->setIConst(safeIndex);
2839 indexConstantUnion->replaceConstantUnion(safeConstantUnion);
2840 }
2841
Jamie Madillb98c3a82015-07-23 14:26:04 -04002842 indexedExpression =
2843 intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002844 }
2845 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002846 else
2847 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002848 if (baseExpression->isInterfaceBlock())
Jamie Madill7164cf42013-07-08 13:30:59 -04002849 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002850 error(
2851 location, "", "[",
2852 "array indexes for interface blocks arrays must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002853 recover();
2854 }
Jamie Madill19571812013-08-12 15:26:34 -07002855 else if (baseExpression->getQualifier() == EvqFragmentOut)
Jamie Madill7164cf42013-07-08 13:30:59 -04002856 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002857 error(location, "", "[",
2858 "array indexes for fragment outputs must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002859 recover();
2860 }
2861
Jamie Madillb98c3a82015-07-23 14:26:04 -04002862 indexedExpression =
2863 intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
Jamie Madill7164cf42013-07-08 13:30:59 -04002864 }
2865
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002866 if (indexedExpression == 0)
2867 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04002868 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002869 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002870 indexedExpression =
2871 intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002872 }
2873 else if (baseExpression->isArray())
2874 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002875 const TType &baseType = baseExpression->getType();
2876 if (baseType.getStruct())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002877 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002878 TType copyOfType(baseType.getStruct());
2879 indexedExpression->setType(copyOfType);
2880 }
2881 else if (baseType.isInterfaceBlock())
2882 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002883 TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(),
2884 baseType.getLayoutQualifier(), 0);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002885 indexedExpression->setType(copyOfType);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002886 }
2887 else
2888 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002889 indexedExpression->setType(
2890 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary,
2891 static_cast<unsigned char>(baseExpression->getNominalSize()),
2892 static_cast<unsigned char>(baseExpression->getSecondarySize())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002893 }
2894
2895 if (baseExpression->getType().getQualifier() == EvqConst)
2896 {
2897 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2898 }
2899 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002900 else if (baseExpression->isMatrix())
2901 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002902 TQualifier qualifier =
2903 baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2904 indexedExpression->setType(TType(baseExpression->getBasicType(),
2905 baseExpression->getPrecision(), qualifier,
2906 static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002907 }
2908 else if (baseExpression->isVector())
2909 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002910 TQualifier qualifier =
2911 baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2912 indexedExpression->setType(
2913 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002914 }
2915 else
2916 {
2917 indexedExpression->setType(baseExpression->getType());
2918 }
2919
2920 return indexedExpression;
2921}
2922
Jamie Madillb98c3a82015-07-23 14:26:04 -04002923TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
2924 const TSourceLoc &dotLocation,
2925 const TString &fieldString,
2926 const TSourceLoc &fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002927{
2928 TIntermTyped *indexedExpression = NULL;
2929
2930 if (baseExpression->isArray())
2931 {
2932 error(fieldLocation, "cannot apply dot operator to an array", ".");
2933 recover();
2934 }
2935
2936 if (baseExpression->isVector())
2937 {
2938 TVectorFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002939 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
2940 fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002941 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002942 fields.num = 1;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002943 fields.offsets[0] = 0;
2944 recover();
2945 }
2946
2947 if (baseExpression->getType().getQualifier() == EvqConst)
2948 {
2949 // constant folding for vector fields
2950 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2951 if (indexedExpression == 0)
2952 {
2953 recover();
2954 indexedExpression = baseExpression;
2955 }
2956 else
2957 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002958 indexedExpression->setType(TType(baseExpression->getBasicType(),
2959 baseExpression->getPrecision(), EvqConst,
2960 (unsigned char)(fieldString).size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002961 }
2962 }
2963 else
2964 {
2965 TString vectorString = fieldString;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302966 TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002967 indexedExpression =
2968 intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
2969 indexedExpression->setType(TType(baseExpression->getBasicType(),
2970 baseExpression->getPrecision(), EvqTemporary,
2971 (unsigned char)vectorString.size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002972 }
2973 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002974 else if (baseExpression->getBasicType() == EbtStruct)
2975 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002976 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302977 const TFieldList &fields = baseExpression->getType().getStruct()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04002978 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002979 {
2980 error(dotLocation, "structure has no fields", "Internal Error");
2981 recover();
2982 indexedExpression = baseExpression;
2983 }
2984 else
2985 {
2986 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002987 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002988 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002989 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002990 {
2991 fieldFound = true;
2992 break;
2993 }
2994 }
2995 if (fieldFound)
2996 {
2997 if (baseExpression->getType().getQualifier() == EvqConst)
2998 {
2999 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
3000 if (indexedExpression == 0)
3001 {
3002 recover();
3003 indexedExpression = baseExpression;
3004 }
3005 else
3006 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003007 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003008 // change the qualifier of the return type, not of the structure field
3009 // as the structure definition is shared between various structures.
3010 indexedExpression->getTypePointer()->setQualifier(EvqConst);
3011 }
3012 }
3013 else
3014 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003015 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003016 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003017 TIntermTyped *index = intermediate.addConstantUnion(
3018 unionArray, *fields[i]->type(), fieldLocation);
3019 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression,
3020 index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003021 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003022 }
3023 }
3024 else
3025 {
3026 error(dotLocation, " no such field in structure", fieldString.c_str());
3027 recover();
3028 indexedExpression = baseExpression;
3029 }
3030 }
3031 }
Jamie Madill98493dd2013-07-08 14:39:03 -04003032 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003033 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003034 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05303035 const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003036 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003037 {
3038 error(dotLocation, "interface block has no fields", "Internal Error");
3039 recover();
3040 indexedExpression = baseExpression;
3041 }
3042 else
3043 {
3044 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003045 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003046 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003047 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003048 {
3049 fieldFound = true;
3050 break;
3051 }
3052 }
3053 if (fieldFound)
3054 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003055 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003056 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003057 TIntermTyped *index =
3058 intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
3059 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock,
3060 baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003061 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003062 }
3063 else
3064 {
3065 error(dotLocation, " no such field in interface block", fieldString.c_str());
3066 recover();
3067 indexedExpression = baseExpression;
3068 }
3069 }
3070 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003071 else
3072 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003073 if (mShaderVersion < 300)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003074 {
Olli Etuaho56193ce2015-08-12 15:55:09 +03003075 error(dotLocation, " field selection requires structure or vector on left hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303076 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003077 }
3078 else
3079 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303080 error(dotLocation,
Olli Etuaho56193ce2015-08-12 15:55:09 +03003081 " field selection requires structure, vector, or interface block on left hand "
3082 "side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303083 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003084 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003085 recover();
3086 indexedExpression = baseExpression;
3087 }
3088
3089 return indexedExpression;
3090}
3091
Jamie Madillb98c3a82015-07-23 14:26:04 -04003092TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3093 const TSourceLoc &qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003094{
Jamie Madilla5efff92013-06-06 11:56:47 -04003095 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003096
Jamie Madillb98c3a82015-07-23 14:26:04 -04003097 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003098 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003099 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003100
3101 if (qualifierType == "shared")
3102 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003103 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003104 }
3105 else if (qualifierType == "packed")
3106 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003107 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003108 }
3109 else if (qualifierType == "std140")
3110 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003111 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003112 }
3113 else if (qualifierType == "row_major")
3114 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003115 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003116 }
3117 else if (qualifierType == "column_major")
3118 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003119 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003120 }
3121 else if (qualifierType == "location")
3122 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003123 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3124 "location requires an argument");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003125 recover();
3126 }
3127 else
3128 {
3129 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
3130 recover();
3131 }
3132
Jamie Madilla5efff92013-06-06 11:56:47 -04003133 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003134}
3135
Jamie Madillb98c3a82015-07-23 14:26:04 -04003136TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3137 const TSourceLoc &qualifierTypeLine,
3138 const TString &intValueString,
3139 int intValue,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303140 const TSourceLoc &intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003141{
Jamie Madilla5efff92013-06-06 11:56:47 -04003142 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003143
Jamie Madillb98c3a82015-07-23 14:26:04 -04003144 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003145 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003146 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003147
3148 if (qualifierType != "location")
3149 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303150 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3151 "only location may have arguments");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003152 recover();
3153 }
3154 else
3155 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04003156 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003157 if (intValue < 0)
3158 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003159 error(intValueLine, "out of range:", intValueString.c_str(),
3160 "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003161 recover();
3162 }
3163 else
3164 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003165 qualifier.location = intValue;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003166 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003167 }
3168
Jamie Madilla5efff92013-06-06 11:56:47 -04003169 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003170}
3171
Jamie Madillb98c3a82015-07-23 14:26:04 -04003172TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
3173 TLayoutQualifier rightQualifier)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003174{
Jamie Madilla5efff92013-06-06 11:56:47 -04003175 TLayoutQualifier joinedQualifier = leftQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003176
Jamie Madilla5efff92013-06-06 11:56:47 -04003177 if (rightQualifier.location != -1)
3178 {
3179 joinedQualifier.location = rightQualifier.location;
3180 }
3181 if (rightQualifier.matrixPacking != EmpUnspecified)
3182 {
3183 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
3184 }
3185 if (rightQualifier.blockStorage != EbsUnspecified)
3186 {
3187 joinedQualifier.blockStorage = rightQualifier.blockStorage;
3188 }
3189
3190 return joinedQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003191}
3192
Arun Patole7e7e68d2015-05-22 12:02:25 +05303193TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
3194 TQualifier interpolationQualifier,
3195 const TSourceLoc &storageLoc,
3196 TQualifier storageQualifier)
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003197{
3198 TQualifier mergedQualifier = EvqSmoothIn;
3199
Arun Patole7e7e68d2015-05-22 12:02:25 +05303200 if (storageQualifier == EvqFragmentIn)
3201 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003202 if (interpolationQualifier == EvqSmooth)
3203 mergedQualifier = EvqSmoothIn;
3204 else if (interpolationQualifier == EvqFlat)
3205 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003206 else
3207 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003208 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303209 else if (storageQualifier == EvqCentroidIn)
3210 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003211 if (interpolationQualifier == EvqSmooth)
3212 mergedQualifier = EvqCentroidIn;
3213 else if (interpolationQualifier == EvqFlat)
3214 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003215 else
3216 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003217 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303218 else if (storageQualifier == EvqVertexOut)
3219 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003220 if (interpolationQualifier == EvqSmooth)
3221 mergedQualifier = EvqSmoothOut;
3222 else if (interpolationQualifier == EvqFlat)
3223 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003224 else
3225 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003226 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303227 else if (storageQualifier == EvqCentroidOut)
3228 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003229 if (interpolationQualifier == EvqSmooth)
3230 mergedQualifier = EvqCentroidOut;
3231 else if (interpolationQualifier == EvqFlat)
3232 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003233 else
3234 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003235 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303236 else
3237 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003238 error(interpolationLoc,
3239 "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303240 getInterpolationString(interpolationQualifier));
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003241 recover();
3242
3243 mergedQualifier = storageQualifier;
3244 }
3245
3246 TPublicType type;
3247 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
3248 return type;
3249}
3250
Jamie Madillb98c3a82015-07-23 14:26:04 -04003251TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
3252 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003253{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03003254 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
3255 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003256 recover();
3257 }
3258
Arun Patole7e7e68d2015-05-22 12:02:25 +05303259 for (unsigned int i = 0; i < fieldList->size(); ++i)
3260 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003261 //
3262 // Careful not to replace already known aspects of type, like array-ness
3263 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303264 TType *type = (*fieldList)[i]->type();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003265 type->setBasicType(typeSpecifier.type);
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003266 type->setPrimarySize(typeSpecifier.primarySize);
3267 type->setSecondarySize(typeSpecifier.secondarySize);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003268 type->setPrecision(typeSpecifier.precision);
3269 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04003270 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003271
3272 // don't allow arrays of arrays
Arun Patole7e7e68d2015-05-22 12:02:25 +05303273 if (type->isArray())
3274 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003275 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
3276 recover();
3277 }
3278 if (typeSpecifier.array)
3279 type->setArraySize(typeSpecifier.arraySize);
Arun Patole7e7e68d2015-05-22 12:02:25 +05303280 if (typeSpecifier.userDef)
3281 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003282 type->setStruct(typeSpecifier.userDef->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003283 }
3284
Arun Patole7e7e68d2015-05-22 12:02:25 +05303285 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i]))
3286 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003287 recover();
3288 }
3289 }
3290
Jamie Madill98493dd2013-07-08 14:39:03 -04003291 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003292}
3293
Jamie Madillb98c3a82015-07-23 14:26:04 -04003294TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
3295 const TSourceLoc &nameLine,
3296 const TString *structName,
3297 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003298{
Arun Patole7e7e68d2015-05-22 12:02:25 +05303299 TStructure *structure = new TStructure(structName, fieldList);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003300 TType *structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003301
Jamie Madill9b820842015-02-12 10:40:10 -05003302 // Store a bool in the struct if we're at global scope, to allow us to
3303 // skip the local struct scoping workaround in HLSL.
Jamie Madillb960cc42015-02-12 15:33:20 +00003304 structure->setUniqueId(TSymbolTable::nextUniqueId());
Jamie Madill9b820842015-02-12 10:40:10 -05003305 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04003306
Jamie Madill98493dd2013-07-08 14:39:03 -04003307 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003308 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003309 if (reservedErrorCheck(nameLine, *structName))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003310 {
3311 recover();
3312 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303313 TVariable *userTypeDef = new TVariable(structName, *structureType, true);
3314 if (!symbolTable.declare(userTypeDef))
3315 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003316 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003317 recover();
3318 }
3319 }
3320
3321 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04003322 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003323 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003324 const TField &field = *(*fieldList)[typeListIndex];
Jamie Madill98493dd2013-07-08 14:39:03 -04003325 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003326 switch (qualifier)
3327 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003328 case EvqGlobal:
3329 case EvqTemporary:
3330 break;
3331 default:
3332 error(field.line(), "invalid qualifier on struct member",
3333 getQualifierString(qualifier));
3334 recover();
3335 break;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003336 }
3337 }
3338
3339 TPublicType publicType;
3340 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04003341 publicType.userDef = structureType;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003342 exitStructDeclaration();
3343
3344 return publicType;
3345}
3346
Jamie Madillb98c3a82015-07-23 14:26:04 -04003347TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
3348 TIntermAggregate *statementList,
3349 const TSourceLoc &loc)
Olli Etuahoa3a36662015-02-17 13:46:51 +02003350{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003351 TBasicType switchType = init->getBasicType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003352 if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
Olli Etuaho53f076f2015-02-20 10:55:14 +02003353 init->isVector())
3354 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003355 error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
3356 "switch");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003357 recover();
3358 return nullptr;
3359 }
3360
Olli Etuahoac5274d2015-02-20 10:19:08 +02003361 if (statementList)
3362 {
3363 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
3364 {
3365 recover();
3366 return nullptr;
3367 }
3368 }
3369
Olli Etuahoa3a36662015-02-17 13:46:51 +02003370 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
3371 if (node == nullptr)
3372 {
3373 error(loc, "erroneous switch statement", "switch");
3374 recover();
3375 return nullptr;
3376 }
3377 return node;
3378}
3379
3380TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
3381{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003382 if (mSwitchNestingLevel == 0)
3383 {
3384 error(loc, "case labels need to be inside switch statements", "case");
3385 recover();
3386 return nullptr;
3387 }
3388 if (condition == nullptr)
3389 {
3390 error(loc, "case label must have a condition", "case");
3391 recover();
3392 return nullptr;
3393 }
3394 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
Jamie Madillb98c3a82015-07-23 14:26:04 -04003395 condition->isMatrix() || condition->isArray() || condition->isVector())
Olli Etuaho53f076f2015-02-20 10:55:14 +02003396 {
3397 error(condition->getLine(), "case label must be a scalar integer", "case");
3398 recover();
3399 }
3400 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
3401 if (conditionConst == nullptr)
3402 {
3403 error(condition->getLine(), "case label must be constant", "case");
3404 recover();
3405 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003406 TIntermCase *node = intermediate.addCase(condition, loc);
3407 if (node == nullptr)
3408 {
3409 error(loc, "erroneous case statement", "case");
3410 recover();
3411 return nullptr;
3412 }
3413 return node;
3414}
3415
3416TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
3417{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003418 if (mSwitchNestingLevel == 0)
3419 {
3420 error(loc, "default labels need to be inside switch statements", "default");
3421 recover();
3422 return nullptr;
3423 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003424 TIntermCase *node = intermediate.addCase(nullptr, loc);
3425 if (node == nullptr)
3426 {
3427 error(loc, "erroneous default statement", "default");
3428 recover();
3429 return nullptr;
3430 }
3431 return node;
3432}
3433
Jamie Madillb98c3a82015-07-23 14:26:04 -04003434TIntermTyped *TParseContext::createUnaryMath(TOperator op,
3435 TIntermTyped *child,
3436 const TSourceLoc &loc,
3437 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02003438{
3439 if (child == nullptr)
3440 {
3441 return nullptr;
3442 }
3443
3444 switch (op)
3445 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003446 case EOpLogicalNot:
3447 if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
3448 child->isVector())
3449 {
3450 return nullptr;
3451 }
3452 break;
3453 case EOpBitwiseNot:
3454 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
3455 child->isMatrix() || child->isArray())
3456 {
3457 return nullptr;
3458 }
3459 break;
3460 case EOpPostIncrement:
3461 case EOpPreIncrement:
3462 case EOpPostDecrement:
3463 case EOpPreDecrement:
3464 case EOpNegative:
3465 case EOpPositive:
3466 if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
3467 child->isArray())
3468 {
3469 return nullptr;
3470 }
3471 // Operators for built-ins are already type checked against their prototype.
3472 default:
3473 break;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003474 }
3475
Olli Etuahof6c694b2015-03-26 14:50:53 +02003476 return intermediate.addUnaryMath(op, child, loc, funcReturnType);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003477}
3478
Olli Etuaho09b22472015-02-11 11:47:26 +02003479TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
3480{
Olli Etuahof6c694b2015-03-26 14:50:53 +02003481 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003482 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02003483 {
3484 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
3485 recover();
3486 return child;
3487 }
3488 return node;
3489}
3490
Jamie Madillb98c3a82015-07-23 14:26:04 -04003491TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
3492 TIntermTyped *child,
3493 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003494{
3495 if (lValueErrorCheck(loc, GetOperatorString(op), child))
3496 recover();
3497 return addUnaryMath(op, child, loc);
3498}
3499
Jamie Madillb98c3a82015-07-23 14:26:04 -04003500bool TParseContext::binaryOpCommonCheck(TOperator op,
3501 TIntermTyped *left,
3502 TIntermTyped *right,
3503 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003504{
3505 if (left->isArray() || right->isArray())
3506 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003507 if (mShaderVersion < 300)
Olli Etuahoe79904c2015-03-18 16:56:42 +02003508 {
3509 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3510 return false;
3511 }
3512
3513 if (left->isArray() != right->isArray())
3514 {
3515 error(loc, "array / non-array mismatch", GetOperatorString(op));
3516 return false;
3517 }
3518
3519 switch (op)
3520 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003521 case EOpEqual:
3522 case EOpNotEqual:
3523 case EOpAssign:
3524 case EOpInitialize:
3525 break;
3526 default:
3527 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3528 return false;
Olli Etuahoe79904c2015-03-18 16:56:42 +02003529 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03003530 // At this point, size of implicitly sized arrays should be resolved.
Olli Etuahoe79904c2015-03-18 16:56:42 +02003531 if (left->getArraySize() != right->getArraySize())
3532 {
3533 error(loc, "array size mismatch", GetOperatorString(op));
3534 return false;
3535 }
Olli Etuahod6b14282015-03-17 14:31:35 +02003536 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003537
3538 // Check ops which require integer / ivec parameters
3539 bool isBitShift = false;
3540 switch (op)
3541 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003542 case EOpBitShiftLeft:
3543 case EOpBitShiftRight:
3544 case EOpBitShiftLeftAssign:
3545 case EOpBitShiftRightAssign:
3546 // Unsigned can be bit-shifted by signed and vice versa, but we need to
3547 // check that the basic type is an integer type.
3548 isBitShift = true;
3549 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
3550 {
3551 return false;
3552 }
3553 break;
3554 case EOpBitwiseAnd:
3555 case EOpBitwiseXor:
3556 case EOpBitwiseOr:
3557 case EOpBitwiseAndAssign:
3558 case EOpBitwiseXorAssign:
3559 case EOpBitwiseOrAssign:
3560 // It is enough to check the type of only one operand, since later it
3561 // is checked that the operand types match.
3562 if (!IsInteger(left->getBasicType()))
3563 {
3564 return false;
3565 }
3566 break;
3567 default:
3568 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003569 }
3570
3571 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
3572 // So the basic type should usually match.
3573 if (!isBitShift && left->getBasicType() != right->getBasicType())
3574 {
3575 return false;
3576 }
3577
Olli Etuaho9dd217b2015-03-20 14:24:31 +02003578 // Check that type sizes match exactly on ops that require that.
Olli Etuahoff699002015-03-23 14:38:42 +02003579 // Also check restrictions for structs that contain arrays or samplers.
Jamie Madillb98c3a82015-07-23 14:26:04 -04003580 switch (op)
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003581 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003582 case EOpAssign:
3583 case EOpInitialize:
3584 case EOpEqual:
3585 case EOpNotEqual:
3586 // ESSL 1.00 sections 5.7, 5.8, 5.9
3587 if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
3588 {
3589 error(loc, "undefined operation for structs containing arrays",
3590 GetOperatorString(op));
3591 return false;
3592 }
3593 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
3594 // we interpret the spec so that this extends to structs containing samplers,
3595 // similarly to ESSL 1.00 spec.
3596 if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
3597 left->getType().isStructureContainingSamplers())
3598 {
3599 error(loc, "undefined operation for structs containing samplers",
3600 GetOperatorString(op));
3601 return false;
3602 }
3603 case EOpLessThan:
3604 case EOpGreaterThan:
3605 case EOpLessThanEqual:
3606 case EOpGreaterThanEqual:
3607 if ((left->getNominalSize() != right->getNominalSize()) ||
3608 (left->getSecondarySize() != right->getSecondarySize()))
3609 {
3610 return false;
3611 }
3612 default:
3613 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003614 }
3615
Olli Etuahod6b14282015-03-17 14:31:35 +02003616 return true;
3617}
3618
Jamie Madillb98c3a82015-07-23 14:26:04 -04003619TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
3620 TIntermTyped *left,
3621 TIntermTyped *right,
3622 const TSourceLoc &loc)
Olli Etuahofc1806e2015-03-17 13:03:11 +02003623{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003624 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003625 return nullptr;
3626
Olli Etuahofc1806e2015-03-17 13:03:11 +02003627 switch (op)
3628 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003629 case EOpEqual:
3630 case EOpNotEqual:
3631 break;
3632 case EOpLessThan:
3633 case EOpGreaterThan:
3634 case EOpLessThanEqual:
3635 case EOpGreaterThanEqual:
3636 ASSERT(!left->isArray() && !right->isArray());
3637 if (left->isMatrix() || left->isVector() || left->getBasicType() == EbtStruct)
3638 {
3639 return nullptr;
3640 }
3641 break;
3642 case EOpLogicalOr:
3643 case EOpLogicalXor:
3644 case EOpLogicalAnd:
3645 ASSERT(!left->isArray() && !right->isArray());
3646 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
3647 {
3648 return nullptr;
3649 }
3650 break;
3651 case EOpAdd:
3652 case EOpSub:
3653 case EOpDiv:
3654 case EOpMul:
3655 ASSERT(!left->isArray() && !right->isArray());
3656 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
3657 {
3658 return nullptr;
3659 }
3660 break;
3661 case EOpIMod:
3662 ASSERT(!left->isArray() && !right->isArray());
3663 // Note that this is only for the % operator, not for mod()
3664 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool ||
3665 left->getBasicType() == EbtFloat)
3666 {
3667 return nullptr;
3668 }
3669 break;
3670 // Note that for bitwise ops, type checking is done in promote() to
3671 // share code between ops and compound assignment
3672 default:
3673 break;
Olli Etuahofc1806e2015-03-17 13:03:11 +02003674 }
3675
Olli Etuahofc1806e2015-03-17 13:03:11 +02003676 return intermediate.addBinaryMath(op, left, right, loc);
3677}
3678
Jamie Madillb98c3a82015-07-23 14:26:04 -04003679TIntermTyped *TParseContext::addBinaryMath(TOperator op,
3680 TIntermTyped *left,
3681 TIntermTyped *right,
3682 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003683{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003684 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003685 if (node == 0)
3686 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003687 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3688 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003689 recover();
3690 return left;
3691 }
3692 return node;
3693}
3694
Jamie Madillb98c3a82015-07-23 14:26:04 -04003695TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
3696 TIntermTyped *left,
3697 TIntermTyped *right,
3698 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003699{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003700 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003701 if (node == 0)
3702 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003703 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3704 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003705 recover();
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003706 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuaho09b22472015-02-11 11:47:26 +02003707 unionArray->setBConst(false);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003708 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
3709 loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003710 }
3711 return node;
3712}
3713
Jamie Madillb98c3a82015-07-23 14:26:04 -04003714TIntermTyped *TParseContext::createAssign(TOperator op,
3715 TIntermTyped *left,
3716 TIntermTyped *right,
3717 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003718{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003719 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003720 {
3721 return intermediate.addAssign(op, left, right, loc);
3722 }
3723 return nullptr;
3724}
3725
Jamie Madillb98c3a82015-07-23 14:26:04 -04003726TIntermTyped *TParseContext::addAssign(TOperator op,
3727 TIntermTyped *left,
3728 TIntermTyped *right,
3729 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003730{
3731 TIntermTyped *node = createAssign(op, left, right, loc);
3732 if (node == nullptr)
3733 {
3734 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
3735 recover();
3736 return left;
3737 }
3738 return node;
3739}
3740
Olli Etuaho49300862015-02-20 14:54:49 +02003741TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
3742{
3743 switch (op)
3744 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003745 case EOpContinue:
3746 if (mLoopNestingLevel <= 0)
3747 {
3748 error(loc, "continue statement only allowed in loops", "");
3749 recover();
3750 }
3751 break;
3752 case EOpBreak:
3753 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
3754 {
3755 error(loc, "break statement only allowed in loops and switch statements", "");
3756 recover();
3757 }
3758 break;
3759 case EOpReturn:
3760 if (mCurrentFunctionType->getBasicType() != EbtVoid)
3761 {
3762 error(loc, "non-void function must return a value", "return");
3763 recover();
3764 }
3765 break;
3766 default:
3767 // No checks for discard
3768 break;
Olli Etuaho49300862015-02-20 14:54:49 +02003769 }
3770 return intermediate.addBranch(op, loc);
3771}
3772
Jamie Madillb98c3a82015-07-23 14:26:04 -04003773TIntermBranch *TParseContext::addBranch(TOperator op,
3774 TIntermTyped *returnValue,
3775 const TSourceLoc &loc)
Olli Etuaho49300862015-02-20 14:54:49 +02003776{
3777 ASSERT(op == EOpReturn);
3778 mFunctionReturnsValue = true;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003779 if (mCurrentFunctionType->getBasicType() == EbtVoid)
Olli Etuaho49300862015-02-20 14:54:49 +02003780 {
3781 error(loc, "void function cannot return a value", "return");
3782 recover();
3783 }
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003784 else if (*mCurrentFunctionType != returnValue->getType())
Olli Etuaho49300862015-02-20 14:54:49 +02003785 {
3786 error(loc, "function return is not matching type:", "return");
3787 recover();
3788 }
3789 return intermediate.addBranch(op, returnValue, loc);
3790}
3791
Jamie Madillb98c3a82015-07-23 14:26:04 -04003792TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
3793 TIntermNode *paramNode,
3794 TIntermNode *thisNode,
3795 const TSourceLoc &loc,
3796 bool *fatalError)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003797{
Jamie Madillb98c3a82015-07-23 14:26:04 -04003798 *fatalError = false;
3799 TOperator op = fnCall->getBuiltInOp();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003800 TIntermTyped *callNode = nullptr;
3801
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003802 if (thisNode != nullptr)
3803 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003804 TConstantUnion *unionArray = new TConstantUnion[1];
Jamie Madillb98c3a82015-07-23 14:26:04 -04003805 int arraySize = 0;
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003806 TIntermTyped *typedThis = thisNode->getAsTyped();
3807 if (fnCall->getName() != "length")
3808 {
3809 error(loc, "invalid method", fnCall->getName().c_str());
3810 recover();
3811 }
3812 else if (paramNode != nullptr)
3813 {
3814 error(loc, "method takes no parameters", "length");
3815 recover();
3816 }
3817 else if (typedThis == nullptr || !typedThis->isArray())
3818 {
3819 error(loc, "length can only be called on arrays", "length");
3820 recover();
3821 }
3822 else
3823 {
Olli Etuaho96e67382015-04-23 14:27:02 +03003824 arraySize = typedThis->getArraySize();
Olli Etuaho39282e12015-04-23 15:41:48 +03003825 if (typedThis->getAsSymbolNode() == nullptr)
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003826 {
Olli Etuaho39282e12015-04-23 15:41:48 +03003827 // This code path can be hit with expressions like these:
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003828 // (a = b).length()
Olli Etuaho39282e12015-04-23 15:41:48 +03003829 // (func()).length()
3830 // (int[3](0, 1, 2)).length()
Jamie Madillb98c3a82015-07-23 14:26:04 -04003831 // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
3832 // expression.
3833 // It allows "An array name with the length method applied" in contrast to GLSL 4.4
3834 // spec section 5.9 which allows "An array, vector or matrix expression with the
3835 // length method applied".
3836 error(loc, "length can only be called on array names, not on array expressions",
3837 "length");
Olli Etuaho39282e12015-04-23 15:41:48 +03003838 recover();
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003839 }
3840 }
Olli Etuaho96e67382015-04-23 14:27:02 +03003841 unionArray->setIConst(arraySize);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003842 callNode =
3843 intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003844 }
3845 else if (op != EOpNull)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003846 {
3847 //
3848 // Then this should be a constructor.
3849 // Don't go through the symbol table for constructors.
3850 // Their parameters will be verified algorithmically.
3851 //
3852 TType type(EbtVoid, EbpUndefined); // use this to get the type back
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003853 if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type))
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003854 {
3855 //
3856 // It's a constructor, of type 'type'.
3857 //
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003858 callNode = addConstructor(paramNode, &type, op, fnCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003859 }
Olli Etuaho72ba85b2015-03-04 14:23:26 +02003860
3861 if (callNode == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003862 {
3863 recover();
3864 callNode = intermediate.setAggregateOperator(nullptr, op, loc);
3865 }
3866 callNode->setType(type);
3867 }
3868 else
3869 {
3870 //
3871 // Not a constructor. Find it in the symbol table.
3872 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303873 const TFunction *fnCandidate;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003874 bool builtIn;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003875 fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003876 if (fnCandidate)
3877 {
3878 //
3879 // A declared function.
3880 //
3881 if (builtIn && !fnCandidate->getExtension().empty() &&
3882 extensionErrorCheck(loc, fnCandidate->getExtension()))
3883 {
3884 recover();
3885 }
3886 op = fnCandidate->getBuiltInOp();
3887 if (builtIn && op != EOpNull)
3888 {
3889 //
3890 // A function call mapped to a built-in operation.
3891 //
3892 if (fnCandidate->getParamCount() == 1)
3893 {
3894 //
3895 // Treat it like a built-in unary operator.
3896 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04003897 callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
3898 &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003899 if (callNode == nullptr)
3900 {
3901 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003902 extraInfoStream
3903 << "built in unary operator function. Type: "
3904 << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003905 std::string extraInfo = extraInfoStream.str();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003906 error(paramNode->getLine(), " wrong operand type", "Internal Error",
3907 extraInfo.c_str());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003908 *fatalError = true;
3909 return nullptr;
3910 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003911 }
3912 else
3913 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003914 TIntermAggregate *aggregate =
3915 intermediate.setAggregateOperator(paramNode, op, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003916 aggregate->setType(fnCandidate->getReturnType());
3917 aggregate->setPrecisionFromChildren();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003918
3919 // Some built-in functions have out parameters too.
3920 functionCallLValueErrorCheck(fnCandidate, aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303921
3922 // See if we can constant fold a built-in.
Olli Etuahob43846e2015-06-02 18:18:57 +03003923 TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303924 if (foldedNode)
3925 {
Arun Patole274f0702015-05-05 13:33:30 +05303926 callNode = foldedNode;
3927 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003928 else
3929 {
3930 callNode = aggregate;
3931 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003932 }
3933 }
3934 else
3935 {
3936 // This is a real function call
3937
Jamie Madillb98c3a82015-07-23 14:26:04 -04003938 TIntermAggregate *aggregate =
3939 intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003940 aggregate->setType(fnCandidate->getReturnType());
3941
Jamie Madillb98c3a82015-07-23 14:26:04 -04003942 // this is how we know whether the given function is a builtIn function or a user
3943 // defined function
3944 // if builtIn == false, it's a userDefined -> could be an overloaded
3945 // builtIn function also
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003946 // if builtIn == true, it's definitely a builtIn function with EOpNull
3947 if (!builtIn)
3948 aggregate->setUserDefined();
3949 aggregate->setName(fnCandidate->getMangledName());
Corentin Wallez71d147f2015-02-11 11:15:24 -08003950 aggregate->setFunctionId(fnCandidate->getUniqueId());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003951
3952 // This needs to happen after the name is set
3953 if (builtIn)
3954 aggregate->setBuiltInFunctionPrecision();
3955
3956 callNode = aggregate;
3957
3958 functionCallLValueErrorCheck(fnCandidate, aggregate);
3959 }
3960 }
3961 else
3962 {
3963 // error message was put out by findFunction()
3964 // Put on a dummy node for error recovery
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003965 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003966 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003967 callNode = intermediate.addConstantUnion(unionArray,
3968 TType(EbtFloat, EbpUndefined, EvqConst), loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003969 recover();
3970 }
3971 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003972 return callNode;
3973}
3974
Jamie Madillb98c3a82015-07-23 14:26:04 -04003975TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
3976 TIntermTyped *trueBlock,
3977 TIntermTyped *falseBlock,
Olli Etuaho52901742015-04-15 13:42:45 +03003978 const TSourceLoc &loc)
3979{
3980 if (boolErrorCheck(loc, cond))
3981 recover();
3982
3983 if (trueBlock->getType() != falseBlock->getType())
3984 {
3985 binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
3986 recover();
3987 return falseBlock;
3988 }
Olli Etuahoa2d53032015-04-15 14:14:44 +03003989 // ESSL1 sections 5.2 and 5.7:
3990 // ESSL3 section 5.7:
3991 // Ternary operator is not among the operators allowed for structures/arrays.
3992 if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
3993 {
3994 error(loc, "ternary operator is not allowed for structures or arrays", ":");
3995 recover();
3996 return falseBlock;
3997 }
Olli Etuaho52901742015-04-15 13:42:45 +03003998 return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
3999}
Olli Etuaho49300862015-02-20 14:54:49 +02004000
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00004001//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004002// Parse an array of strings using yyparse.
4003//
4004// Returns 0 for success.
4005//
Jamie Madillb98c3a82015-07-23 14:26:04 -04004006int PaParseStrings(size_t count,
4007 const char *const string[],
4008 const int length[],
Arun Patole7e7e68d2015-05-22 12:02:25 +05304009 TParseContext *context)
4010{
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004011 if ((count == 0) || (string == NULL))
4012 return 1;
4013
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004014 if (glslang_initialize(context))
4015 return 1;
4016
alokp@chromium.org408c45e2012-04-05 15:54:43 +00004017 int error = glslang_scan(count, string, length, context);
4018 if (!error)
4019 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004020
alokp@chromium.org73bc2982012-06-19 18:48:05 +00004021 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00004022
alokp@chromium.org6b495712012-06-29 00:06:58 +00004023 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004024}