blob: 8d05d1ea7664880ea3988095c5d2ec735d5dcd13 [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
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001185TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
1186 const TString *name,
1187 const TSymbol *symbol)
1188{
1189 const TVariable *variable = getNamedVariable(location, name, symbol);
1190
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001191 if (variable->getType().getQualifier() == EvqConst && variable->getConstPointer())
Olli Etuaho82c29ed2015-11-03 13:06:54 +02001192 {
1193 TConstantUnion *constArray = variable->getConstPointer();
1194 TType t(variable->getType());
1195 return intermediate.addConstantUnion(constArray, t, location);
1196 }
1197 else
1198 {
1199 return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
1200 variable->getType(), location);
1201 }
1202}
1203
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001204//
1205// Look up a function name in the symbol table, and make sure it is a function.
1206//
1207// Return the function symbol if found, otherwise 0.
1208//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001209const TFunction *TParseContext::findFunction(const TSourceLoc &line,
1210 TFunction *call,
1211 int inputShaderVersion,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301212 bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001213{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001214 // First find by unmangled name to check whether the function name has been
1215 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001216 // If a function is found, check for one with a matching argument list.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301217 const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
1218 if (symbol == 0 || symbol->isFunction())
1219 {
Austin Kinross3ae64652015-01-26 15:51:39 -08001220 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001221 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001222
Arun Patole7e7e68d2015-05-22 12:02:25 +05301223 if (symbol == 0)
1224 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001225 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001226 return 0;
1227 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228
Arun Patole7e7e68d2015-05-22 12:02:25 +05301229 if (!symbol->isFunction())
1230 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001231 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001232 return 0;
1233 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001234
Jamie Madillb98c3a82015-07-23 14:26:04 -04001235 return static_cast<const TFunction *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001236}
1237
1238//
1239// Initializers show up in several places in the grammar. Have one set of
1240// code to handle them here.
1241//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001242// Returns true on error, false if no error
1243//
Jamie Madillb98c3a82015-07-23 14:26:04 -04001244bool TParseContext::executeInitializer(const TSourceLoc &line,
1245 const TString &identifier,
1246 const TPublicType &pType,
1247 TIntermTyped *initializer,
1248 TIntermNode **intermNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001249{
Olli Etuahoe7847b02015-03-16 11:56:12 +02001250 ASSERT(intermNode != nullptr);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001251 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001252
Olli Etuaho2935c582015-04-08 14:32:06 +03001253 TVariable *variable = nullptr;
Olli Etuaho376f1b52015-04-13 13:23:41 +03001254 if (type.isUnsizedArray())
1255 {
1256 type.setArraySize(initializer->getArraySize());
1257 }
Olli Etuaho2935c582015-04-08 14:32:06 +03001258 if (!declareVariable(line, identifier, type, &variable))
1259 {
1260 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001261 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001262
Olli Etuahob0c645e2015-05-12 14:25:36 +03001263 bool globalInitWarning = false;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001264 if (symbolTable.atGlobalLevel() &&
1265 !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
Olli Etuahob0c645e2015-05-12 14:25:36 +03001266 {
1267 // Error message does not completely match behavior with ESSL 1.00, but
1268 // we want to steer developers towards only using constant expressions.
1269 error(line, "global variable initializers must be constant expressions", "=");
1270 return true;
1271 }
1272 if (globalInitWarning)
1273 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001274 warning(
1275 line,
1276 "global variable initializers should be constant expressions "
1277 "(uniforms and globals are allowed in global initializers for legacy compatibility)",
1278 "=");
Olli Etuahob0c645e2015-05-12 14:25:36 +03001279 }
1280
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001281 //
1282 // identifier must be of type constant, a global, or a temporary
1283 //
1284 TQualifier qualifier = variable->getType().getQualifier();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301285 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
1286 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001287 error(line, " cannot initialize this type of qualifier ",
1288 variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001289 return true;
1290 }
1291 //
1292 // test for and propagate constant
1293 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001294
Arun Patole7e7e68d2015-05-22 12:02:25 +05301295 if (qualifier == EvqConst)
1296 {
1297 if (qualifier != initializer->getType().getQualifier())
1298 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001299 std::stringstream extraInfoStream;
1300 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1301 std::string extraInfo = extraInfoStream.str();
1302 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001303 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001304 return true;
1305 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05301306 if (type != initializer->getType())
1307 {
1308 error(line, " non-matching types for const initializer ",
Jamie Madillb98c3a82015-07-23 14:26:04 -04001309 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001310 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001311 return true;
1312 }
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001313
1314 // Save the constant folded value to the variable if possible. For example array
1315 // initializers are not folded, since that way copying the array literal to multiple places
1316 // in the shader is avoided.
1317 // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
1318 // it would be beneficial.
Arun Patole7e7e68d2015-05-22 12:02:25 +05301319 if (initializer->getAsConstantUnion())
1320 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001321 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001322 *intermNode = nullptr;
1323 return false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05301324 }
1325 else if (initializer->getAsSymbolNode())
1326 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001327 const TSymbol *symbol =
1328 symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1329 const TVariable *tVar = static_cast<const TVariable *>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001330
Arun Patole7e7e68d2015-05-22 12:02:25 +05301331 TConstantUnion *constArray = tVar->getConstPointer();
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001332 if (constArray)
1333 {
1334 variable->shareConstPointer(constArray);
1335 *intermNode = nullptr;
1336 return false;
1337 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001338 }
1339 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001340
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001341 TIntermSymbol *intermSymbol = intermediate.addSymbol(
1342 variable->getUniqueId(), variable->getName(), variable->getType(), line);
1343 *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
1344 if (*intermNode == nullptr)
Olli Etuahoe7847b02015-03-16 11:56:12 +02001345 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02001346 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1347 return true;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001348 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001350 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001351}
1352
Arun Patole7e7e68d2015-05-22 12:02:25 +05301353bool TParseContext::areAllChildConst(TIntermAggregate *aggrNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001354{
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001355 ASSERT(aggrNode != NULL);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001356 if (!aggrNode->isConstructor())
1357 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001358
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001359 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001360
Arun Patole7e7e68d2015-05-22 12:02:25 +05301361 // check if all the child nodes are constants so that they can be inserted into
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001362 // the parent node
Jamie Madillb98c3a82015-07-23 14:26:04 -04001363 TIntermSequence *sequence = aggrNode->getSequence();
Arun Patole7e7e68d2015-05-22 12:02:25 +05301364 for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p)
1365 {
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001366 if (!(*p)->getAsTyped()->getAsConstantUnion())
1367 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001368 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001369
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001370 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001371}
1372
Jamie Madillb98c3a82015-07-23 14:26:04 -04001373TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
1374 bool invariant,
1375 TLayoutQualifier layoutQualifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301376 const TPublicType &typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001377{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001378 TPublicType returnType = typeSpecifier;
1379 returnType.qualifier = qualifier;
1380 returnType.invariant = invariant;
Jamie Madilla5efff92013-06-06 11:56:47 -04001381 returnType.layoutQualifier = layoutQualifier;
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001382
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001383 if (mShaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001384 {
Olli Etuahoc1ac41b2015-07-10 13:53:46 +03001385 if (typeSpecifier.array)
1386 {
1387 error(typeSpecifier.line, "not supported", "first-class array");
1388 recover();
1389 returnType.clearArrayness();
1390 }
1391
Jamie Madillb98c3a82015-07-23 14:26:04 -04001392 if (qualifier == EvqAttribute &&
1393 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001394 {
1395 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1396 recover();
1397 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001398
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001399 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1400 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1401 {
1402 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1403 recover();
1404 }
1405 }
1406 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001407 {
Olli Etuahoabb0c382015-07-13 12:01:12 +03001408 if (!layoutQualifier.isEmpty())
1409 {
1410 if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout"))
1411 {
1412 recover();
1413 }
1414 }
Olli Etuahocc36b982015-07-10 14:14:18 +03001415 if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001416 {
Olli Etuahocc36b982015-07-10 14:14:18 +03001417 es3InputOutputTypeCheck(qualifier, typeSpecifier, typeSpecifier.line);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001418 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001419 }
1420
1421 return returnType;
1422}
1423
Olli Etuahocc36b982015-07-10 14:14:18 +03001424void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier,
1425 const TPublicType &type,
1426 const TSourceLoc &qualifierLocation)
1427{
1428 // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
1429 if (type.type == EbtBool)
1430 {
1431 error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
1432 recover();
1433 }
1434
1435 // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
1436 switch (qualifier)
1437 {
1438 case EvqVertexIn:
1439 // ESSL 3.00 section 4.3.4
1440 if (type.array)
1441 {
1442 error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
1443 recover();
1444 }
1445 // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
1446 return;
1447 case EvqFragmentOut:
1448 // ESSL 3.00 section 4.3.6
1449 if (type.isMatrix())
1450 {
1451 error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
1452 recover();
1453 }
1454 // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
1455 return;
1456 default:
1457 break;
1458 }
1459
1460 // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
1461 // restrictions.
1462 bool typeContainsIntegers =
1463 (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) ||
1464 type.isStructureContainingType(EbtUInt));
1465 if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
1466 {
1467 error(qualifierLocation, "must use 'flat' interpolation here",
1468 getQualifierString(qualifier));
1469 recover();
1470 }
1471
1472 if (type.type == EbtStruct)
1473 {
1474 // ESSL 3.00 sections 4.3.4 and 4.3.6.
1475 // These restrictions are only implied by the ESSL 3.00 spec, but
1476 // the ESSL 3.10 spec lists these restrictions explicitly.
1477 if (type.array)
1478 {
1479 error(qualifierLocation, "cannot be an array of structures",
1480 getQualifierString(qualifier));
1481 recover();
1482 }
1483 if (type.isStructureContainingArrays())
1484 {
1485 error(qualifierLocation, "cannot be a structure containing an array",
1486 getQualifierString(qualifier));
1487 recover();
1488 }
1489 if (type.isStructureContainingType(EbtStruct))
1490 {
1491 error(qualifierLocation, "cannot be a structure containing a structure",
1492 getQualifierString(qualifier));
1493 recover();
1494 }
1495 if (type.isStructureContainingType(EbtBool))
1496 {
1497 error(qualifierLocation, "cannot be a structure containing a bool",
1498 getQualifierString(qualifier));
1499 recover();
1500 }
1501 }
1502}
1503
Olli Etuahofa33d582015-04-09 14:33:12 +03001504TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
1505 const TSourceLoc &identifierOrTypeLocation,
1506 const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001507{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001508 TIntermSymbol *symbol =
1509 intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001510
Olli Etuahobab4c082015-04-24 16:38:49 +03001511 bool emptyDeclaration = (identifier == "");
Olli Etuahofa33d582015-04-09 14:33:12 +03001512
Olli Etuahobab4c082015-04-24 16:38:49 +03001513 mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
1514
1515 if (emptyDeclaration)
1516 {
1517 if (publicType.isUnsizedArray())
1518 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001519 // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
1520 // error. It is assumed that this applies to empty declarations as well.
1521 error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
1522 identifier.c_str());
Olli Etuahobab4c082015-04-24 16:38:49 +03001523 }
1524 }
1525 else
Jamie Madill60ed9812013-06-06 11:56:46 -04001526 {
Olli Etuahofa33d582015-04-09 14:33:12 +03001527 if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001528 recover();
1529
Olli Etuaho376f1b52015-04-13 13:23:41 +03001530 if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001531 recover();
1532
Olli Etuaho2935c582015-04-08 14:32:06 +03001533 TVariable *variable = nullptr;
Olli Etuahofa33d582015-04-09 14:33:12 +03001534 if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001535 recover();
1536
1537 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001538 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001539 }
1540
Olli Etuahoe7847b02015-03-16 11:56:12 +02001541 return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001542}
1543
Olli Etuahoe7847b02015-03-16 11:56:12 +02001544TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
1545 const TSourceLoc &identifierLocation,
1546 const TString &identifier,
1547 const TSourceLoc &indexLocation,
1548 TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001549{
Olli Etuahofa33d582015-04-09 14:33:12 +03001550 mDeferredSingleDeclarationErrorCheck = false;
1551
1552 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001553 recover();
1554
Olli Etuaho376f1b52015-04-13 13:23:41 +03001555 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001556 recover();
1557
Jamie Madillb98c3a82015-07-23 14:26:04 -04001558 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1559 arrayQualifierErrorCheck(indexLocation, publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001560 {
1561 recover();
1562 }
1563
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001564 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001565
1566 int size;
1567 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1568 {
1569 recover();
1570 }
Olli Etuahoe7847b02015-03-16 11:56:12 +02001571 // Make the type an array even if size check failed.
1572 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1573 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001574
Olli Etuaho2935c582015-04-08 14:32:06 +03001575 TVariable *variable = nullptr;
1576 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001577 recover();
1578
Olli Etuahoe7847b02015-03-16 11:56:12 +02001579 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001580 if (variable && symbol)
Jamie Madill60ed9812013-06-06 11:56:46 -04001581 symbol->setId(variable->getUniqueId());
Jamie Madill60ed9812013-06-06 11:56:46 -04001582
Olli Etuahoe7847b02015-03-16 11:56:12 +02001583 return intermediate.makeAggregate(symbol, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001584}
1585
Jamie Madill06145232015-05-13 13:10:01 -04001586TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
Olli Etuahoe7847b02015-03-16 11:56:12 +02001587 const TSourceLoc &identifierLocation,
1588 const TString &identifier,
1589 const TSourceLoc &initLocation,
1590 TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001591{
Olli Etuahofa33d582015-04-09 14:33:12 +03001592 mDeferredSingleDeclarationErrorCheck = false;
1593
1594 if (singleDeclarationErrorCheck(publicType, identifierLocation))
Jamie Madill60ed9812013-06-06 11:56:46 -04001595 recover();
1596
Olli Etuahoe7847b02015-03-16 11:56:12 +02001597 TIntermNode *intermNode = nullptr;
1598 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill60ed9812013-06-06 11:56:46 -04001599 {
1600 //
1601 // Build intermediate representation
1602 //
Olli Etuahoe7847b02015-03-16 11:56:12 +02001603 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001604 }
1605 else
1606 {
1607 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001608 return nullptr;
Jamie Madill60ed9812013-06-06 11:56:46 -04001609 }
1610}
1611
Jamie Madillb98c3a82015-07-23 14:26:04 -04001612TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
1613 TPublicType &publicType,
1614 const TSourceLoc &identifierLocation,
1615 const TString &identifier,
1616 const TSourceLoc &indexLocation,
1617 TIntermTyped *indexExpression,
1618 const TSourceLoc &initLocation,
1619 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001620{
1621 mDeferredSingleDeclarationErrorCheck = false;
1622
1623 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1624 recover();
1625
Jamie Madillb98c3a82015-07-23 14:26:04 -04001626 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1627 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001628 {
1629 recover();
1630 }
1631
1632 TPublicType arrayType(publicType);
1633
Olli Etuaho376f1b52015-04-13 13:23:41 +03001634 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001635 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1636 // the initializer.
1637 if (indexExpression != nullptr &&
1638 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001639 {
1640 recover();
1641 }
1642 // Make the type an array even if size check failed.
1643 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1644 arrayType.setArraySize(size);
1645
1646 // initNode will correspond to the whole of "type b[n] = initializer".
1647 TIntermNode *initNode = nullptr;
1648 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1649 {
1650 return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
1651 }
1652 else
1653 {
1654 recover();
1655 return nullptr;
1656 }
1657}
1658
Olli Etuahoe7847b02015-03-16 11:56:12 +02001659TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
Jamie Madill47e3ec02014-08-20 16:38:33 -04001660 const TSourceLoc &identifierLoc,
1661 const TString *identifier,
1662 const TSymbol *symbol)
1663{
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001664 // invariant declaration
Jamie Madill47e3ec02014-08-20 16:38:33 -04001665 if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
1666 {
1667 recover();
1668 }
1669
1670 if (!symbol)
1671 {
1672 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
1673 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001674 return nullptr;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001675 }
1676 else
1677 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001678 const TString kGlFrontFacing("gl_FrontFacing");
1679 if (*identifier == kGlFrontFacing)
1680 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001681 error(identifierLoc, "identifier should not be declared as invariant",
1682 identifier->c_str());
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001683 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001684 return nullptr;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001685 }
Jamie Madill2c433252014-12-03 12:36:54 -05001686 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001687 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
1688 ASSERT(variable);
1689 const TType &type = variable->getType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04001690 TIntermSymbol *intermSymbol =
1691 intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001692
1693 TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
1694 aggregate->setOp(EOpInvariantDeclaration);
1695 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001696 }
1697}
1698
Jamie Madillb98c3a82015-07-23 14:26:04 -04001699TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
1700 TIntermAggregate *aggregateDeclaration,
1701 const TSourceLoc &identifierLocation,
1702 const TString &identifier)
Jamie Madill502d66f2013-06-20 11:55:52 -04001703{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001704 // If the declaration starting this declarator list was empty (example: int,), some checks were
1705 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001706 if (mDeferredSingleDeclarationErrorCheck)
1707 {
1708 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1709 recover();
1710 mDeferredSingleDeclarationErrorCheck = false;
1711 }
1712
Jamie Madill0bd18df2013-06-20 11:55:52 -04001713 if (locationDeclaratorListCheck(identifierLocation, publicType))
1714 recover();
1715
Olli Etuaho376f1b52015-04-13 13:23:41 +03001716 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001717 recover();
1718
Olli Etuaho2935c582015-04-08 14:32:06 +03001719 TVariable *variable = nullptr;
1720 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001721 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001722
Jamie Madillb98c3a82015-07-23 14:26:04 -04001723 TIntermSymbol *symbol =
1724 intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001725 if (variable && symbol)
Jamie Madill502d66f2013-06-20 11:55:52 -04001726 symbol->setId(variable->getUniqueId());
1727
Olli Etuahoe7847b02015-03-16 11:56:12 +02001728 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001729}
1730
Jamie Madillb98c3a82015-07-23 14:26:04 -04001731TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
1732 TIntermAggregate *aggregateDeclaration,
1733 const TSourceLoc &identifierLocation,
1734 const TString &identifier,
1735 const TSourceLoc &arrayLocation,
1736 TIntermTyped *indexExpression)
Jamie Madill502d66f2013-06-20 11:55:52 -04001737{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001738 // If the declaration starting this declarator list was empty (example: int,), some checks were
1739 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001740 if (mDeferredSingleDeclarationErrorCheck)
1741 {
1742 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1743 recover();
1744 mDeferredSingleDeclarationErrorCheck = false;
1745 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001746
Jamie Madill0bd18df2013-06-20 11:55:52 -04001747 if (locationDeclaratorListCheck(identifierLocation, publicType))
1748 recover();
1749
Olli Etuaho376f1b52015-04-13 13:23:41 +03001750 if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001751 recover();
1752
Jamie Madillb98c3a82015-07-23 14:26:04 -04001753 if (arrayTypeErrorCheck(arrayLocation, publicType) ||
1754 arrayQualifierErrorCheck(arrayLocation, publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001755 {
1756 recover();
1757 }
Olli Etuaho93a90fd2015-04-07 18:14:07 +03001758 else
Jamie Madill502d66f2013-06-20 11:55:52 -04001759 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001760 TType arrayType = TType(publicType);
Jamie Madill502d66f2013-06-20 11:55:52 -04001761 int size;
1762 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
Olli Etuahoe7847b02015-03-16 11:56:12 +02001763 {
Jamie Madill502d66f2013-06-20 11:55:52 -04001764 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001765 }
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001766 arrayType.setArraySize(size);
Olli Etuahoe7847b02015-03-16 11:56:12 +02001767
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001768 TVariable *variable = nullptr;
Olli Etuahoe7847b02015-03-16 11:56:12 +02001769 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001770 recover();
Jamie Madill502d66f2013-06-20 11:55:52 -04001771
Jamie Madillb98c3a82015-07-23 14:26:04 -04001772 TIntermSymbol *symbol =
1773 intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001774 if (variable && symbol)
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001775 symbol->setId(variable->getUniqueId());
Olli Etuahoe7847b02015-03-16 11:56:12 +02001776
1777 return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001778 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001779
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001780 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001781}
1782
Jamie Madillb98c3a82015-07-23 14:26:04 -04001783TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
1784 TIntermAggregate *aggregateDeclaration,
1785 const TSourceLoc &identifierLocation,
1786 const TString &identifier,
1787 const TSourceLoc &initLocation,
1788 TIntermTyped *initializer)
Jamie Madill502d66f2013-06-20 11:55:52 -04001789{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001790 // If the declaration starting this declarator list was empty (example: int,), some checks were
1791 // not performed.
Olli Etuahofa33d582015-04-09 14:33:12 +03001792 if (mDeferredSingleDeclarationErrorCheck)
1793 {
1794 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1795 recover();
1796 mDeferredSingleDeclarationErrorCheck = false;
1797 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001798
Jamie Madill0bd18df2013-06-20 11:55:52 -04001799 if (locationDeclaratorListCheck(identifierLocation, publicType))
1800 recover();
1801
Olli Etuahoe7847b02015-03-16 11:56:12 +02001802 TIntermNode *intermNode = nullptr;
1803 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
Jamie Madill502d66f2013-06-20 11:55:52 -04001804 {
1805 //
1806 // build the intermediate representation
1807 //
1808 if (intermNode)
1809 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001810 return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001811 }
1812 else
1813 {
Olli Etuahoe7847b02015-03-16 11:56:12 +02001814 return aggregateDeclaration;
Jamie Madill502d66f2013-06-20 11:55:52 -04001815 }
1816 }
1817 else
1818 {
1819 recover();
Olli Etuahoe7847b02015-03-16 11:56:12 +02001820 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001821 }
1822}
1823
Jamie Madill06145232015-05-13 13:10:01 -04001824TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001825 TIntermAggregate *aggregateDeclaration,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301826 const TSourceLoc &identifierLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001827 const TString &identifier,
Arun Patole7e7e68d2015-05-22 12:02:25 +05301828 const TSourceLoc &indexLocation,
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001829 TIntermTyped *indexExpression,
Jamie Madillb98c3a82015-07-23 14:26:04 -04001830 const TSourceLoc &initLocation,
1831 TIntermTyped *initializer)
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001832{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001833 // If the declaration starting this declarator list was empty (example: int,), some checks were
1834 // not performed.
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001835 if (mDeferredSingleDeclarationErrorCheck)
1836 {
1837 if (singleDeclarationErrorCheck(publicType, identifierLocation))
1838 recover();
1839 mDeferredSingleDeclarationErrorCheck = false;
1840 }
1841
1842 if (locationDeclaratorListCheck(identifierLocation, publicType))
1843 recover();
1844
Jamie Madillb98c3a82015-07-23 14:26:04 -04001845 if (arrayTypeErrorCheck(indexLocation, publicType) ||
1846 arrayQualifierErrorCheck(indexLocation, publicType))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001847 {
1848 recover();
1849 }
1850
1851 TPublicType arrayType(publicType);
1852
Olli Etuaho376f1b52015-04-13 13:23:41 +03001853 int size = 0;
Jamie Madillb98c3a82015-07-23 14:26:04 -04001854 // If indexExpression is nullptr, then the array will eventually get its size implicitly from
1855 // the initializer.
1856 if (indexExpression != nullptr &&
1857 arraySizeErrorCheck(identifierLocation, indexExpression, size))
Olli Etuaho3875ffd2015-04-10 16:45:14 +03001858 {
1859 recover();
1860 }
1861 // Make the type an array even if size check failed.
1862 // This ensures useless error messages regarding the variable's non-arrayness won't follow.
1863 arrayType.setArraySize(size);
1864
1865 // initNode will correspond to the whole of "b[n] = initializer".
1866 TIntermNode *initNode = nullptr;
1867 if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
1868 {
1869 if (initNode)
1870 {
1871 return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
1872 }
1873 else
1874 {
1875 return aggregateDeclaration;
1876 }
1877 }
1878 else
1879 {
1880 recover();
1881 return nullptr;
1882 }
1883}
1884
Jamie Madilla295edf2013-06-06 11:56:48 -04001885void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1886{
1887 if (typeQualifier.qualifier != EvqUniform)
1888 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001889 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
1890 "global layout must be uniform");
Jamie Madilla295edf2013-06-06 11:56:48 -04001891 recover();
1892 return;
1893 }
1894
1895 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1896 ASSERT(!layoutQualifier.isEmpty());
1897
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001898 if (mShaderVersion < 300)
Jamie Madilla295edf2013-06-06 11:56:48 -04001899 {
1900 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1901 recover();
1902 return;
1903 }
1904
1905 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1906 {
1907 recover();
1908 return;
1909 }
1910
Jamie Madill099c0f32013-06-20 11:55:52 -04001911 if (layoutQualifier.matrixPacking != EmpUnspecified)
1912 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001913 mDefaultMatrixPacking = layoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04001914 }
1915
Geoff Langc6856732014-02-11 09:38:55 -05001916 if (layoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001917 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04001918 mDefaultBlockStorage = layoutQualifier.blockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04001919 }
Jamie Madilla295edf2013-06-06 11:56:48 -04001920}
1921
Jamie Madill185fb402015-06-12 15:48:48 -04001922void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
1923 TFunction *function,
1924 TIntermAggregate **aggregateOut)
1925{
Jamie Madillb98c3a82015-07-23 14:26:04 -04001926 const TSymbol *builtIn =
1927 symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04001928
1929 if (builtIn)
1930 {
1931 error(location, "built-in functions cannot be redefined", function->getName().c_str());
1932 recover();
1933 }
1934
Jamie Madillb98c3a82015-07-23 14:26:04 -04001935 TFunction *prevDec =
1936 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
Jamie Madill185fb402015-06-12 15:48:48 -04001937 //
1938 // Note: 'prevDec' could be 'function' if this is the first time we've seen function
1939 // as it would have just been put in the symbol table. Otherwise, we're looking up
1940 // an earlier occurance.
1941 //
1942 if (prevDec->isDefined())
1943 {
1944 // Then this function already has a body.
1945 error(location, "function already has a body", function->getName().c_str());
1946 recover();
1947 }
1948 prevDec->setDefined();
1949 //
1950 // Overload the unique ID of the definition to be the same unique ID as the declaration.
1951 // Eventually we will probably want to have only a single definition and just swap the
1952 // arguments to be the definition's arguments.
1953 //
1954 function->setUniqueId(prevDec->getUniqueId());
1955
1956 // Raise error message if main function takes any parameters or return anything other than void
1957 if (function->getName() == "main")
1958 {
1959 if (function->getParamCount() > 0)
1960 {
1961 error(location, "function cannot take any parameter(s)", function->getName().c_str());
1962 recover();
1963 }
1964 if (function->getReturnType().getBasicType() != EbtVoid)
1965 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04001966 error(location, "", function->getReturnType().getBasicString(),
1967 "main function cannot return a value");
Jamie Madill185fb402015-06-12 15:48:48 -04001968 recover();
1969 }
1970 }
1971
1972 //
1973 // Remember the return type for later checking for RETURN statements.
1974 //
1975 setCurrentFunctionType(&(prevDec->getReturnType()));
1976 setFunctionReturnsValue(false);
1977
1978 //
1979 // Insert parameters into the symbol table.
1980 // If the parameter has no name, it's not an error, just don't insert it
1981 // (could be used for unused args).
1982 //
1983 // Also, accumulate the list of parameters into the HIL, so lower level code
1984 // knows where to find parameters.
1985 //
1986 TIntermAggregate *paramNodes = new TIntermAggregate;
1987 for (size_t i = 0; i < function->getParamCount(); i++)
1988 {
1989 const TConstParameter &param = function->getParam(i);
1990 if (param.name != 0)
1991 {
1992 TVariable *variable = new TVariable(param.name, *param.type);
1993 //
1994 // Insert the parameters with name in the symbol table.
1995 //
Jamie Madill1a4b1b32015-07-23 18:27:13 -04001996 if (!symbolTable.declare(variable))
1997 {
Jamie Madill185fb402015-06-12 15:48:48 -04001998 error(location, "redefinition", variable->getName().c_str());
1999 recover();
Jamie Madill1a4b1b32015-07-23 18:27:13 -04002000 paramNodes = intermediate.growAggregate(
2001 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
2002 continue;
Jamie Madill185fb402015-06-12 15:48:48 -04002003 }
2004
2005 //
2006 // Add the parameter to the HIL
2007 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002008 TIntermSymbol *symbol = intermediate.addSymbol(
2009 variable->getUniqueId(), variable->getName(), variable->getType(), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002010
2011 paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
2012 }
2013 else
2014 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002015 paramNodes = intermediate.growAggregate(
2016 paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
Jamie Madill185fb402015-06-12 15:48:48 -04002017 }
2018 }
2019 intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
2020 *aggregateOut = paramNodes;
2021 setLoopNestingLevel(0);
2022}
2023
Jamie Madillb98c3a82015-07-23 14:26:04 -04002024TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
Jamie Madill185fb402015-06-12 15:48:48 -04002025{
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002026 //
2027 // Multiple declarations of the same function are allowed.
2028 //
2029 // If this is a definition, the definition production code will check for redefinitions
2030 // (we don't know at this point if it's a definition or not).
2031 //
2032 // Redeclarations are allowed. But, return types and parameter qualifiers must match.
2033 //
2034 TFunction *prevDec =
2035 static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
2036 if (prevDec)
Jamie Madill185fb402015-06-12 15:48:48 -04002037 {
2038 if (prevDec->getReturnType() != function->getReturnType())
2039 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002040 error(location, "overloaded functions must have the same return type",
Jamie Madill185fb402015-06-12 15:48:48 -04002041 function->getReturnType().getBasicString());
2042 recover();
2043 }
2044 for (size_t i = 0; i < prevDec->getParamCount(); ++i)
2045 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002046 if (prevDec->getParam(i).type->getQualifier() !=
2047 function->getParam(i).type->getQualifier())
Jamie Madill185fb402015-06-12 15:48:48 -04002048 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002049 error(location, "overloaded functions must have the same parameter qualifiers",
Jamie Madill185fb402015-06-12 15:48:48 -04002050 function->getParam(i).type->getQualifierString());
2051 recover();
2052 }
2053 }
2054 }
2055
2056 //
2057 // Check for previously declared variables using the same name.
2058 //
Geoff Lang13e7c7e2015-07-30 14:17:29 +00002059 TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
Jamie Madill185fb402015-06-12 15:48:48 -04002060 if (prevSym)
2061 {
2062 if (!prevSym->isFunction())
2063 {
2064 error(location, "redefinition", function->getName().c_str(), "function");
2065 recover();
2066 }
2067 }
2068 else
2069 {
2070 // Insert the unmangled name to detect potential future redefinition as a variable.
Jamie Madillb98c3a82015-07-23 14:26:04 -04002071 TFunction *newFunction =
2072 new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
Jamie Madill185fb402015-06-12 15:48:48 -04002073 symbolTable.getOuterLevel()->insertUnmangled(newFunction);
2074 }
2075
2076 // We're at the inner scope level of the function's arguments and body statement.
2077 // Add the function prototype to the surrounding scope instead.
2078 symbolTable.getOuterLevel()->insert(function);
2079
2080 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04002081 // If this is a redeclaration, it could also be a definition, in which case, we want to use the
2082 // variable names from this one, and not the one that's
Jamie Madill185fb402015-06-12 15:48:48 -04002083 // being redeclared. So, pass back up this declaration, not the one in the symbol table.
2084 //
2085 return function;
2086}
2087
Jamie Madill06145232015-05-13 13:10:01 -04002088TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002089{
Jamie Madill06145232015-05-13 13:10:01 -04002090 TPublicType publicType = publicTypeIn;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002091 TOperator op = EOpNull;
2092 if (publicType.userDef)
2093 {
2094 op = EOpConstructStruct;
2095 }
2096 else
2097 {
2098 switch (publicType.type)
2099 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002100 case EbtFloat:
2101 if (publicType.isMatrix())
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002102 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002103 switch (publicType.getCols())
Alexis Hetu07e57df2015-06-16 16:55:52 -04002104 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002105 case 2:
2106 switch (publicType.getRows())
2107 {
2108 case 2:
2109 op = EOpConstructMat2;
2110 break;
2111 case 3:
2112 op = EOpConstructMat2x3;
2113 break;
2114 case 4:
2115 op = EOpConstructMat2x4;
2116 break;
2117 }
2118 break;
2119 case 3:
2120 switch (publicType.getRows())
2121 {
2122 case 2:
2123 op = EOpConstructMat3x2;
2124 break;
2125 case 3:
2126 op = EOpConstructMat3;
2127 break;
2128 case 4:
2129 op = EOpConstructMat3x4;
2130 break;
2131 }
2132 break;
2133 case 4:
2134 switch (publicType.getRows())
2135 {
2136 case 2:
2137 op = EOpConstructMat4x2;
2138 break;
2139 case 3:
2140 op = EOpConstructMat4x3;
2141 break;
2142 case 4:
2143 op = EOpConstructMat4;
2144 break;
2145 }
2146 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -04002147 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002148 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002149 else
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002150 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002151 switch (publicType.getNominalSize())
2152 {
2153 case 1:
2154 op = EOpConstructFloat;
2155 break;
2156 case 2:
2157 op = EOpConstructVec2;
2158 break;
2159 case 3:
2160 op = EOpConstructVec3;
2161 break;
2162 case 4:
2163 op = EOpConstructVec4;
2164 break;
2165 }
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002166 }
Jamie Madillb98c3a82015-07-23 14:26:04 -04002167 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002168
Jamie Madillb98c3a82015-07-23 14:26:04 -04002169 case EbtInt:
2170 switch (publicType.getNominalSize())
2171 {
2172 case 1:
2173 op = EOpConstructInt;
2174 break;
2175 case 2:
2176 op = EOpConstructIVec2;
2177 break;
2178 case 3:
2179 op = EOpConstructIVec3;
2180 break;
2181 case 4:
2182 op = EOpConstructIVec4;
2183 break;
2184 }
2185 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002186
Jamie Madillb98c3a82015-07-23 14:26:04 -04002187 case EbtUInt:
2188 switch (publicType.getNominalSize())
2189 {
2190 case 1:
2191 op = EOpConstructUInt;
2192 break;
2193 case 2:
2194 op = EOpConstructUVec2;
2195 break;
2196 case 3:
2197 op = EOpConstructUVec3;
2198 break;
2199 case 4:
2200 op = EOpConstructUVec4;
2201 break;
2202 }
2203 break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00002204
Jamie Madillb98c3a82015-07-23 14:26:04 -04002205 case EbtBool:
2206 switch (publicType.getNominalSize())
2207 {
2208 case 1:
2209 op = EOpConstructBool;
2210 break;
2211 case 2:
2212 op = EOpConstructBVec2;
2213 break;
2214 case 3:
2215 op = EOpConstructBVec3;
2216 break;
2217 case 4:
2218 op = EOpConstructBVec4;
2219 break;
2220 }
2221 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002222
Jamie Madillb98c3a82015-07-23 14:26:04 -04002223 default:
2224 break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002225 }
2226
2227 if (op == EOpNull)
2228 {
2229 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
2230 recover();
2231 publicType.type = EbtFloat;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002232 op = EOpConstructFloat;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002233 }
2234 }
2235
2236 TString tempString;
Dmitry Skiba7f17a502015-06-22 15:08:39 -07002237 const TType *type = new TType(publicType);
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00002238 return new TFunction(&tempString, type, op);
2239}
2240
Jamie Madillb98c3a82015-07-23 14:26:04 -04002241// This function is used to test for the correctness of the parameters passed to various constructor
2242// functions and also convert them to the right datatype if it is allowed and required.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002243//
2244// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
2245//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002246TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
2247 TType *type,
2248 TOperator op,
2249 TFunction *fnCall,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302250 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002251{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002252 TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002253
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002254 if (!aggregateArguments)
2255 {
2256 aggregateArguments = new TIntermAggregate;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07002257 aggregateArguments->getSequence()->push_back(arguments);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002258 }
2259
Olli Etuahof40319e2015-03-10 14:33:00 +02002260 if (type->isArray())
2261 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002262 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
2263 // the array.
Olli Etuahof40319e2015-03-10 14:33:00 +02002264 TIntermSequence *args = aggregateArguments->getSequence();
2265 for (size_t i = 0; i < args->size(); i++)
2266 {
2267 const TType &argType = (*args)[i]->getAsTyped()->getType();
2268 // It has already been checked that the argument is not an array.
2269 ASSERT(!argType.isArray());
2270 if (!argType.sameElementType(*type))
2271 {
2272 error(line, "Array constructor argument has an incorrect type", "Error");
2273 recover();
2274 return nullptr;
2275 }
2276 }
2277 }
2278 else if (op == EOpConstructStruct)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002279 {
2280 const TFieldList &fields = type->getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002281 TIntermSequence *args = aggregateArguments->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002282
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002283 for (size_t i = 0; i < fields.size(); i++)
2284 {
Nicolas Capensffd73872014-08-21 13:49:16 -04002285 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002286 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002287 error(line, "Structure constructor arguments do not match structure fields",
2288 "Error");
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002289 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002290
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002291 return 0;
2292 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002293 }
2294 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002295
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002296 // Turn the argument list itself into a constructor
Jamie Madillb98c3a82015-07-23 14:26:04 -04002297 TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
Olli Etuaho21203702014-11-13 16:16:21 +02002298 TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002299 if (constConstructor)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002300 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002301 return constConstructor;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002302 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002303
Olli Etuaho21203702014-11-13 16:16:21 +02002304 // Structs should not be precision qualified, the individual members may be.
2305 // Built-in types on the other hand should be precision qualified.
2306 if (op != EOpConstructStruct)
2307 {
2308 constructor->setPrecisionFromChildren();
2309 type->setPrecision(constructor->getPrecision());
2310 }
2311
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002312 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002313}
2314
Arun Patole7e7e68d2015-05-22 12:02:25 +05302315TIntermTyped *TParseContext::foldConstConstructor(TIntermAggregate *aggrNode, const TType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002316{
Olli Etuahof40319e2015-03-10 14:33:00 +02002317 // TODO: Add support for folding array constructors
2318 bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002319 aggrNode->setType(type);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302320 if (canBeFolded)
2321 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002322 bool returnVal = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302323 TConstantUnion *unionArray = new TConstantUnion[type.getObjectSize()];
2324 if (aggrNode->getSequence()->size() == 1)
2325 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002326 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2327 aggrNode->getOp(), type, true);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002328 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302329 else
2330 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002331 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray,
2332 aggrNode->getOp(), type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002333 }
2334 if (returnVal)
2335 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002336
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002337 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
2338 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002339
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002340 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002341}
2342
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002343//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002344// This function returns the tree representation for the vector field(s) being accessed from contant
2345// vector.
2346// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a
2347// contant node is returned, else an aggregate node is returned (for v.xy). The input to this
2348// function could either
2349// be the symbol node or it could be the intermediate tree representation of accessing fields in a
2350// constant
2351// structure or column of a constant matrix.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002352//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002353TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields,
2354 TIntermTyped *node,
2355 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002356{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302357 TIntermTyped *typedNode;
2358 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002359
Jamie Madillb11e2482015-05-04 14:21:22 -04002360 const TConstantUnion *unionArray;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302361 if (tempConstantNode)
2362 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002363 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002364
Arun Patole7e7e68d2015-05-22 12:02:25 +05302365 if (!unionArray)
2366 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002367 return node;
2368 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302369 }
2370 else
Jamie Madillb98c3a82015-07-23 14:26:04 -04002371 { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else,
2372 // its an error
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002373 error(line, "Cannot offset into the vector", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002374 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002375
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002376 return 0;
2377 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002378
Arun Patole7e7e68d2015-05-22 12:02:25 +05302379 TConstantUnion *constArray = new TConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002380
Arun Patole7e7e68d2015-05-22 12:02:25 +05302381 for (int i = 0; i < fields.num; i++)
2382 {
2383 if (fields.offsets[i] >= node->getType().getNominalSize())
2384 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002385 std::stringstream extraInfoStream;
2386 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
2387 std::string extraInfo = extraInfoStream.str();
2388 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002389 recover();
2390 fields.offsets[i] = 0;
2391 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302392
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002393 constArray[i] = unionArray[fields.offsets[i]];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302394 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002395 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
2396 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002397}
2398
2399//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002400// This function returns the column being accessed from a constant matrix. The values are retrieved
2401// from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector).
2402// The
2403// input to the function could either be a symbol node (m[0] where m is a constant matrix)that
2404// represents
2405// a constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s
2406// is a constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002407//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002408TIntermTyped *TParseContext::addConstMatrixNode(int index,
2409 TIntermTyped *node,
2410 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002411{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302412 TIntermTyped *typedNode;
2413 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002414
Arun Patole7e7e68d2015-05-22 12:02:25 +05302415 if (index >= node->getType().getCols())
2416 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002417 std::stringstream extraInfoStream;
2418 extraInfoStream << "matrix field selection out of range '" << index << "'";
2419 std::string extraInfo = extraInfoStream.str();
2420 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002421 recover();
2422 index = 0;
2423 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002424
Arun Patole7e7e68d2015-05-22 12:02:25 +05302425 if (tempConstantNode)
2426 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002427 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
2428 int size = tempConstantNode->getType().getCols();
2429 typedNode = intermediate.addConstantUnion(&unionArray[size * index],
2430 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302431 }
2432 else
2433 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002434 error(line, "Cannot offset into the matrix", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002435 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002436
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002437 return 0;
2438 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002439
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002440 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002441}
2442
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002443//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002444// This function returns an element of an array accessed from a constant array. The values are
2445// 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 +05302446// 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 -04002447// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a
2448// constant structure)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002449//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002450TIntermTyped *TParseContext::addConstArrayNode(int index,
2451 TIntermTyped *node,
2452 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002453{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302454 TIntermTyped *typedNode;
2455 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002456 TType arrayElementType = node->getType();
2457 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002458
Arun Patole7e7e68d2015-05-22 12:02:25 +05302459 if (index >= node->getType().getArraySize())
2460 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002461 std::stringstream extraInfoStream;
2462 extraInfoStream << "array field selection out of range '" << index << "'";
2463 std::string extraInfo = extraInfoStream.str();
2464 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002465 recover();
2466 index = 0;
2467 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002468
Arun Patole7e7e68d2015-05-22 12:02:25 +05302469 if (tempConstantNode)
2470 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002471 size_t arrayElementSize = arrayElementType.getObjectSize();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302472 TConstantUnion *unionArray = tempConstantNode->getUnionArrayPointer();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002473 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index],
2474 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302475 }
2476 else
2477 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002478 error(line, "Cannot offset into the array", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002479 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002480
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002481 return 0;
2482 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002483
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002484 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002485}
2486
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002487//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002488// This function returns the value of a particular field inside a constant structure from the symbol
2489// table.
2490// If there is an embedded/nested struct, it appropriately calls addConstStructNested or
2491// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
2492// struct.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002493//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002494TIntermTyped *TParseContext::addConstStruct(const TString &identifier,
2495 TIntermTyped *node,
2496 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002497{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302498 const TFieldList &fields = node->getType().getStruct()->fields();
Jamie Madillb98c3a82015-07-23 14:26:04 -04002499 size_t instanceSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002500
Arun Patole7e7e68d2015-05-22 12:02:25 +05302501 for (size_t index = 0; index < fields.size(); ++index)
2502 {
2503 if (fields[index]->name() == identifier)
2504 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002505 break;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302506 }
2507 else
2508 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002509 instanceSize += fields[index]->type()->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002510 }
2511 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002512
Jamie Madill94bf7f22013-07-08 13:31:15 -04002513 TIntermTyped *typedNode;
2514 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
Arun Patole7e7e68d2015-05-22 12:02:25 +05302515 if (tempConstantNode)
2516 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002517 TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002518
Jamie Madillb98c3a82015-07-23 14:26:04 -04002519 // type will be changed in the calling function
2520 typedNode = intermediate.addConstantUnion(constArray + instanceSize,
2521 tempConstantNode->getType(), line);
Arun Patole7e7e68d2015-05-22 12:02:25 +05302522 }
2523 else
2524 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002525 error(line, "Cannot offset into the structure", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002526 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002527
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002528 return 0;
2529 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002530
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00002531 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002532}
2533
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002534//
2535// Interface/uniform blocks
2536//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002537TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualifier,
2538 const TSourceLoc &nameLine,
2539 const TString &blockName,
2540 TFieldList *fieldList,
2541 const TString *instanceName,
2542 const TSourceLoc &instanceLine,
2543 TIntermTyped *arrayIndex,
2544 const TSourceLoc &arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002545{
2546 if (reservedErrorCheck(nameLine, blockName))
2547 recover();
2548
2549 if (typeQualifier.qualifier != EvqUniform)
2550 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302551 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
2552 "interface blocks must be uniform");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002553 recover();
2554 }
2555
Jamie Madill099c0f32013-06-20 11:55:52 -04002556 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
2557 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002558 {
2559 recover();
2560 }
2561
Jamie Madill099c0f32013-06-20 11:55:52 -04002562 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
2563 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002564 blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002565 }
2566
Jamie Madill1566ef72013-06-20 11:55:54 -04002567 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
2568 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002569 blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
Jamie Madill1566ef72013-06-20 11:55:54 -04002570 }
2571
Arun Patole7e7e68d2015-05-22 12:02:25 +05302572 TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
2573 if (!symbolTable.declare(blockNameSymbol))
2574 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002575 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
2576 recover();
2577 }
2578
Jamie Madill98493dd2013-07-08 14:39:03 -04002579 // check for sampler types and apply layout qualifiers
Arun Patole7e7e68d2015-05-22 12:02:25 +05302580 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2581 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002582 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302583 TType *fieldType = field->type();
2584 if (IsSampler(fieldType->getBasicType()))
2585 {
2586 error(field->line(), "unsupported type", fieldType->getBasicString(),
2587 "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002588 recover();
2589 }
2590
Jamie Madill98493dd2013-07-08 14:39:03 -04002591 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002592 switch (qualifier)
2593 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002594 case EvqGlobal:
2595 case EvqUniform:
2596 break;
2597 default:
2598 error(field->line(), "invalid qualifier on interface block member",
2599 getQualifierString(qualifier));
2600 recover();
2601 break;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002602 }
Jamie Madilla5efff92013-06-06 11:56:47 -04002603
2604 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04002605 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
2606 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04002607 {
2608 recover();
2609 }
Jamie Madill099c0f32013-06-20 11:55:52 -04002610
Jamie Madill98493dd2013-07-08 14:39:03 -04002611 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04002612 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002613 error(field->line(), "invalid layout qualifier:",
2614 getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04002615 recover();
2616 }
2617
Jamie Madill98493dd2013-07-08 14:39:03 -04002618 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04002619 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002620 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04002621 }
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002622 else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
Jamie Madill099c0f32013-06-20 11:55:52 -04002623 {
Olli Etuahofb6ab2c2015-07-09 20:55:28 +03002624 warning(field->line(), "extraneous layout qualifier:",
Jamie Madillb98c3a82015-07-23 14:26:04 -04002625 getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
2626 "only has an effect on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04002627 }
2628
Jamie Madill98493dd2013-07-08 14:39:03 -04002629 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002630 }
2631
Jamie Madill98493dd2013-07-08 14:39:03 -04002632 // add array index
2633 int arraySize = 0;
2634 if (arrayIndex != NULL)
2635 {
2636 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
2637 recover();
2638 }
2639
Jamie Madillb98c3a82015-07-23 14:26:04 -04002640 TInterfaceBlock *interfaceBlock =
2641 new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
2642 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
2643 arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002644
2645 TString symbolName = "";
Jamie Madillb98c3a82015-07-23 14:26:04 -04002646 int symbolId = 0;
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002647
Jamie Madill98493dd2013-07-08 14:39:03 -04002648 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002649 {
2650 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04002651 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
2652 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002653 TField *field = (*fieldList)[memberIndex];
Arun Patole7e7e68d2015-05-22 12:02:25 +05302654 TType *fieldType = field->type();
Jamie Madill98493dd2013-07-08 14:39:03 -04002655
2656 // set parent pointer of the field variable
2657 fieldType->setInterfaceBlock(interfaceBlock);
2658
Arun Patole7e7e68d2015-05-22 12:02:25 +05302659 TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
Jamie Madill98493dd2013-07-08 14:39:03 -04002660 fieldVariable->setQualifier(typeQualifier.qualifier);
2661
Arun Patole7e7e68d2015-05-22 12:02:25 +05302662 if (!symbolTable.declare(fieldVariable))
2663 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002664 error(field->line(), "redefinition", field->name().c_str(),
2665 "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002666 recover();
2667 }
2668 }
2669 }
2670 else
2671 {
Olli Etuahoe0f623a2015-07-10 11:58:30 +03002672 if (reservedErrorCheck(instanceLine, *instanceName))
2673 recover();
2674
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002675 // add a symbol for this interface block
Arun Patole7e7e68d2015-05-22 12:02:25 +05302676 TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002677 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04002678
Arun Patole7e7e68d2015-05-22 12:02:25 +05302679 if (!symbolTable.declare(instanceTypeDef))
2680 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002681 error(instanceLine, "redefinition", instanceName->c_str(),
2682 "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002683 recover();
2684 }
2685
Jamie Madillb98c3a82015-07-23 14:26:04 -04002686 symbolId = instanceTypeDef->getUniqueId();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002687 symbolName = instanceTypeDef->getName();
2688 }
2689
Jamie Madillb98c3a82015-07-23 14:26:04 -04002690 TIntermAggregate *aggregate = intermediate.makeAggregate(
2691 intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
2692 nameLine);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002693 aggregate->setOp(EOpDeclaration);
Jamie Madill98493dd2013-07-08 14:39:03 -04002694
2695 exitStructDeclaration();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002696 return aggregate;
2697}
2698
Arun Patole7e7e68d2015-05-22 12:02:25 +05302699bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002700{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002701 ++mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002702
2703 // Embedded structure definitions are not supported per GLSL ES spec.
2704 // They aren't allowed in GLSL either, but we need to detect this here
2705 // so we don't rely on the GLSL compiler to catch it.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302706 if (mStructNestingLevel > 1)
2707 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002708 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002709 return true;
2710 }
2711
2712 return false;
2713}
2714
2715void TParseContext::exitStructDeclaration()
2716{
Jamie Madill6e06b1f2015-05-14 10:01:17 -04002717 --mStructNestingLevel;
kbr@chromium.org476541f2011-10-27 21:14:51 +00002718}
2719
Jamie Madillb98c3a82015-07-23 14:26:04 -04002720namespace
2721{
kbr@chromium.org476541f2011-10-27 21:14:51 +00002722const int kWebGLMaxStructNesting = 4;
2723
2724} // namespace
2725
Arun Patole7e7e68d2015-05-22 12:02:25 +05302726bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00002727{
Arun Patole7e7e68d2015-05-22 12:02:25 +05302728 if (!IsWebGLBasedSpec(mShaderSpec))
2729 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002730 return false;
2731 }
2732
Arun Patole7e7e68d2015-05-22 12:02:25 +05302733 if (field.type()->getBasicType() != EbtStruct)
2734 {
kbr@chromium.org476541f2011-10-27 21:14:51 +00002735 return false;
2736 }
2737
2738 // We're already inside a structure definition at this point, so add
2739 // one to the field's struct nesting.
Arun Patole7e7e68d2015-05-22 12:02:25 +05302740 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
2741 {
Jamie Madill41a49272014-03-18 16:10:13 -04002742 std::stringstream reasonStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002743 reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
2744 << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
Jamie Madill41a49272014-03-18 16:10:13 -04002745 std::string reason = reasonStream.str();
2746 error(line, reason.c_str(), field.name().c_str(), "");
kbr@chromium.org476541f2011-10-27 21:14:51 +00002747 return true;
2748 }
2749
2750 return false;
2751}
2752
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00002753//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002754// Parse an array index expression
2755//
Jamie Madillb98c3a82015-07-23 14:26:04 -04002756TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
2757 const TSourceLoc &location,
Arun Patole7e7e68d2015-05-22 12:02:25 +05302758 TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002759{
2760 TIntermTyped *indexedExpression = NULL;
2761
2762 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2763 {
2764 if (baseExpression->getAsSymbolNode())
2765 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05302766 error(location, " left of '[' is not of type array, matrix, or vector ",
2767 baseExpression->getAsSymbolNode()->getSymbol().c_str());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002768 }
2769 else
2770 {
2771 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2772 }
2773 recover();
2774 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002775
Jamie Madill21c1e452014-12-29 11:33:41 -05002776 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2777
2778 if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04002779 {
Jamie Madill21c1e452014-12-29 11:33:41 -05002780 int index = indexConstantUnion->getIConst(0);
Jamie Madill7164cf42013-07-08 13:30:59 -04002781 if (index < 0)
2782 {
2783 std::stringstream infoStream;
2784 infoStream << index;
2785 std::string info = infoStream.str();
2786 error(location, "negative index", info.c_str());
2787 recover();
2788 index = 0;
2789 }
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002790 if (baseExpression->getType().getQualifier() == EvqConst &&
2791 baseExpression->getAsConstantUnion())
Jamie Madill7164cf42013-07-08 13:30:59 -04002792 {
2793 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002794 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002795 // constant folding for array indexing
Jamie Madill7164cf42013-07-08 13:30:59 -04002796 indexedExpression = addConstArrayNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002797 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002798 else if (baseExpression->isVector())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002799 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002800 // constant folding for vector indexing
Jamie Madill7164cf42013-07-08 13:30:59 -04002801 TVectorFields fields;
2802 fields.num = 1;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002803 fields.offsets[0] =
2804 index; // need to do it this way because v.xy sends fields integer array
Jamie Madill7164cf42013-07-08 13:30:59 -04002805 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2806 }
2807 else if (baseExpression->isMatrix())
2808 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002809 // constant folding for matrix indexing
Jamie Madill7164cf42013-07-08 13:30:59 -04002810 indexedExpression = addConstMatrixNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002811 }
2812 }
2813 else
2814 {
Jamie Madillb11e2482015-05-04 14:21:22 -04002815 int safeIndex = -1;
2816
Jamie Madill7164cf42013-07-08 13:30:59 -04002817 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002818 {
Jamie Madill18464b52013-07-08 14:01:55 -04002819 if (index >= baseExpression->getType().getArraySize())
Jamie Madill7164cf42013-07-08 13:30:59 -04002820 {
2821 std::stringstream extraInfoStream;
2822 extraInfoStream << "array index out of range '" << index << "'";
2823 std::string extraInfo = extraInfoStream.str();
2824 error(location, "", "[", extraInfo.c_str());
2825 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002826 safeIndex = baseExpression->getType().getArraySize() - 1;
Jamie Madill7164cf42013-07-08 13:30:59 -04002827 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302828 else if (baseExpression->getQualifier() == EvqFragData && index > 0 &&
2829 !isExtensionEnabled("GL_EXT_draw_buffers"))
Jamie Madill5d287f52013-07-12 15:38:19 -04002830 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002831 error(location, "", "[",
2832 "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is "
2833 "disabled");
Jamie Madill5d287f52013-07-12 15:38:19 -04002834 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002835 safeIndex = 0;
Jamie Madill5d287f52013-07-12 15:38:19 -04002836 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002837 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05302838 else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
Jamie Madillb98c3a82015-07-23 14:26:04 -04002839 baseExpression->getType().getNominalSize() <= index)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002840 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002841 std::stringstream extraInfoStream;
2842 extraInfoStream << "field selection out of range '" << index << "'";
2843 std::string extraInfo = extraInfoStream.str();
2844 error(location, "", "[", extraInfo.c_str());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002845 recover();
Jamie Madillb11e2482015-05-04 14:21:22 -04002846 safeIndex = baseExpression->getType().getNominalSize() - 1;
Jamie Madill46131a32013-06-20 11:55:50 -04002847 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002848
Jamie Madillb11e2482015-05-04 14:21:22 -04002849 // Don't modify the data of the previous constant union, because it can point
2850 // to builtins, like gl_MaxDrawBuffers. Instead use a new sanitized object.
2851 if (safeIndex != -1)
2852 {
2853 TConstantUnion *safeConstantUnion = new TConstantUnion();
2854 safeConstantUnion->setIConst(safeIndex);
2855 indexConstantUnion->replaceConstantUnion(safeConstantUnion);
2856 }
2857
Jamie Madillb98c3a82015-07-23 14:26:04 -04002858 indexedExpression =
2859 intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002860 }
2861 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002862 else
2863 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002864 if (baseExpression->isInterfaceBlock())
Jamie Madill7164cf42013-07-08 13:30:59 -04002865 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002866 error(
2867 location, "", "[",
2868 "array indexes for interface blocks arrays must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002869 recover();
2870 }
Jamie Madill19571812013-08-12 15:26:34 -07002871 else if (baseExpression->getQualifier() == EvqFragmentOut)
Jamie Madill7164cf42013-07-08 13:30:59 -04002872 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002873 error(location, "", "[",
2874 "array indexes for fragment outputs must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002875 recover();
2876 }
2877
Jamie Madillb98c3a82015-07-23 14:26:04 -04002878 indexedExpression =
2879 intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
Jamie Madill7164cf42013-07-08 13:30:59 -04002880 }
2881
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002882 if (indexedExpression == 0)
2883 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04002884 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002885 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002886 indexedExpression =
2887 intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002888 }
2889 else if (baseExpression->isArray())
2890 {
Olli Etuahob3fbd862015-09-30 17:55:02 +03002891 TType indexedType = baseExpression->getType();
2892 indexedType.clearArrayness();
2893 indexedExpression->setType(indexedType);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002894 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002895 else if (baseExpression->isMatrix())
2896 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002897 indexedExpression->setType(TType(baseExpression->getBasicType(),
Olli Etuahob3fbd862015-09-30 17:55:02 +03002898 baseExpression->getPrecision(), EvqTemporary,
Jamie Madillb98c3a82015-07-23 14:26:04 -04002899 static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002900 }
2901 else if (baseExpression->isVector())
2902 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002903 indexedExpression->setType(
Olli Etuahob3fbd862015-09-30 17:55:02 +03002904 TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002905 }
2906 else
2907 {
2908 indexedExpression->setType(baseExpression->getType());
2909 }
2910
Olli Etuahob3fbd862015-09-30 17:55:02 +03002911 if (baseExpression->getType().getQualifier() == EvqConst &&
2912 indexExpression->getType().getQualifier() == EvqConst)
2913 {
2914 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2915 }
2916 else
2917 {
2918 indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
2919 }
2920
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002921 return indexedExpression;
2922}
2923
Jamie Madillb98c3a82015-07-23 14:26:04 -04002924TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
2925 const TSourceLoc &dotLocation,
2926 const TString &fieldString,
2927 const TSourceLoc &fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002928{
2929 TIntermTyped *indexedExpression = NULL;
2930
2931 if (baseExpression->isArray())
2932 {
2933 error(fieldLocation, "cannot apply dot operator to an array", ".");
2934 recover();
2935 }
2936
2937 if (baseExpression->isVector())
2938 {
2939 TVectorFields fields;
Jamie Madillb98c3a82015-07-23 14:26:04 -04002940 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
2941 fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002942 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002943 fields.num = 1;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002944 fields.offsets[0] = 0;
2945 recover();
2946 }
2947
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002948 if (baseExpression->getType().getQualifier() == EvqConst &&
2949 baseExpression->getAsConstantUnion())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002950 {
2951 // constant folding for vector fields
2952 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2953 if (indexedExpression == 0)
2954 {
2955 recover();
2956 indexedExpression = baseExpression;
2957 }
2958 else
2959 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002960 indexedExpression->setType(TType(baseExpression->getBasicType(),
2961 baseExpression->getPrecision(), EvqConst,
2962 (unsigned char)(fieldString).size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002963 }
2964 }
2965 else
2966 {
2967 TString vectorString = fieldString;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302968 TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
Jamie Madillb98c3a82015-07-23 14:26:04 -04002969 indexedExpression =
2970 intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
2971 indexedExpression->setType(TType(baseExpression->getBasicType(),
2972 baseExpression->getPrecision(), EvqTemporary,
2973 (unsigned char)vectorString.size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002974 }
2975 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002976 else if (baseExpression->getBasicType() == EbtStruct)
2977 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04002978 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05302979 const TFieldList &fields = baseExpression->getType().getStruct()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04002980 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002981 {
2982 error(dotLocation, "structure has no fields", "Internal Error");
2983 recover();
2984 indexedExpression = baseExpression;
2985 }
2986 else
2987 {
2988 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002989 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002990 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002991 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002992 {
2993 fieldFound = true;
2994 break;
2995 }
2996 }
2997 if (fieldFound)
2998 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +02002999 if (baseExpression->getType().getQualifier() == EvqConst &&
3000 baseExpression->getAsConstantUnion())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003001 {
3002 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
3003 if (indexedExpression == 0)
3004 {
3005 recover();
3006 indexedExpression = baseExpression;
3007 }
3008 else
3009 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003010 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003011 // change the qualifier of the return type, not of the structure field
3012 // as the structure definition is shared between various structures.
3013 indexedExpression->getTypePointer()->setQualifier(EvqConst);
3014 }
3015 }
3016 else
3017 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003018 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003019 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003020 TIntermTyped *index = intermediate.addConstantUnion(
3021 unionArray, *fields[i]->type(), fieldLocation);
3022 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression,
3023 index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003024 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003025 }
3026 }
3027 else
3028 {
3029 error(dotLocation, " no such field in structure", fieldString.c_str());
3030 recover();
3031 indexedExpression = baseExpression;
3032 }
3033 }
3034 }
Jamie Madill98493dd2013-07-08 14:39:03 -04003035 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003036 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003037 bool fieldFound = false;
Arun Patole7e7e68d2015-05-22 12:02:25 +05303038 const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04003039 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003040 {
3041 error(dotLocation, "interface block has no fields", "Internal Error");
3042 recover();
3043 indexedExpression = baseExpression;
3044 }
3045 else
3046 {
3047 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04003048 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003049 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003050 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003051 {
3052 fieldFound = true;
3053 break;
3054 }
3055 }
3056 if (fieldFound)
3057 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003058 TConstantUnion *unionArray = new TConstantUnion[1];
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003059 unionArray->setIConst(i);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003060 TIntermTyped *index =
3061 intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
3062 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock,
3063 baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04003064 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003065 }
3066 else
3067 {
3068 error(dotLocation, " no such field in interface block", fieldString.c_str());
3069 recover();
3070 indexedExpression = baseExpression;
3071 }
3072 }
3073 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003074 else
3075 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003076 if (mShaderVersion < 300)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003077 {
Olli Etuaho56193ce2015-08-12 15:55:09 +03003078 error(dotLocation, " field selection requires structure or vector on left hand side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303079 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003080 }
3081 else
3082 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303083 error(dotLocation,
Olli Etuaho56193ce2015-08-12 15:55:09 +03003084 " field selection requires structure, vector, or interface block on left hand "
3085 "side",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303086 fieldString.c_str());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00003087 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003088 recover();
3089 indexedExpression = baseExpression;
3090 }
3091
Olli Etuahob1edc4f2015-11-02 17:20:03 +02003092 if (baseExpression->getQualifier() == EvqConst)
3093 {
3094 indexedExpression->getTypePointer()->setQualifier(EvqConst);
3095 }
3096
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003097 return indexedExpression;
3098}
3099
Jamie Madillb98c3a82015-07-23 14:26:04 -04003100TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3101 const TSourceLoc &qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003102{
Jamie Madilla5efff92013-06-06 11:56:47 -04003103 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003104
Jamie Madillb98c3a82015-07-23 14:26:04 -04003105 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003106 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003107 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003108
3109 if (qualifierType == "shared")
3110 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003111 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003112 }
3113 else if (qualifierType == "packed")
3114 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003115 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003116 }
3117 else if (qualifierType == "std140")
3118 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003119 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003120 }
3121 else if (qualifierType == "row_major")
3122 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003123 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003124 }
3125 else if (qualifierType == "column_major")
3126 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003127 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003128 }
3129 else if (qualifierType == "location")
3130 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003131 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3132 "location requires an argument");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003133 recover();
3134 }
3135 else
3136 {
3137 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
3138 recover();
3139 }
3140
Jamie Madilla5efff92013-06-06 11:56:47 -04003141 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003142}
3143
Jamie Madillb98c3a82015-07-23 14:26:04 -04003144TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
3145 const TSourceLoc &qualifierTypeLine,
3146 const TString &intValueString,
3147 int intValue,
Arun Patole7e7e68d2015-05-22 12:02:25 +05303148 const TSourceLoc &intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003149{
Jamie Madilla5efff92013-06-06 11:56:47 -04003150 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003151
Jamie Madillb98c3a82015-07-23 14:26:04 -04003152 qualifier.location = -1;
Jamie Madilla5efff92013-06-06 11:56:47 -04003153 qualifier.matrixPacking = EmpUnspecified;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003154 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003155
3156 if (qualifierType != "location")
3157 {
Arun Patole7e7e68d2015-05-22 12:02:25 +05303158 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
3159 "only location may have arguments");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003160 recover();
3161 }
3162 else
3163 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04003164 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003165 if (intValue < 0)
3166 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003167 error(intValueLine, "out of range:", intValueString.c_str(),
3168 "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003169 recover();
3170 }
3171 else
3172 {
Jamie Madilla5efff92013-06-06 11:56:47 -04003173 qualifier.location = intValue;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003174 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003175 }
3176
Jamie Madilla5efff92013-06-06 11:56:47 -04003177 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003178}
3179
Jamie Madillb98c3a82015-07-23 14:26:04 -04003180TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
3181 TLayoutQualifier rightQualifier)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003182{
Jamie Madilla5efff92013-06-06 11:56:47 -04003183 TLayoutQualifier joinedQualifier = leftQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003184
Jamie Madilla5efff92013-06-06 11:56:47 -04003185 if (rightQualifier.location != -1)
3186 {
3187 joinedQualifier.location = rightQualifier.location;
3188 }
3189 if (rightQualifier.matrixPacking != EmpUnspecified)
3190 {
3191 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
3192 }
3193 if (rightQualifier.blockStorage != EbsUnspecified)
3194 {
3195 joinedQualifier.blockStorage = rightQualifier.blockStorage;
3196 }
3197
3198 return joinedQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00003199}
3200
Arun Patole7e7e68d2015-05-22 12:02:25 +05303201TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
3202 TQualifier interpolationQualifier,
3203 const TSourceLoc &storageLoc,
3204 TQualifier storageQualifier)
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003205{
3206 TQualifier mergedQualifier = EvqSmoothIn;
3207
Arun Patole7e7e68d2015-05-22 12:02:25 +05303208 if (storageQualifier == EvqFragmentIn)
3209 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003210 if (interpolationQualifier == EvqSmooth)
3211 mergedQualifier = EvqSmoothIn;
3212 else if (interpolationQualifier == EvqFlat)
3213 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003214 else
3215 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003216 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303217 else if (storageQualifier == EvqCentroidIn)
3218 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003219 if (interpolationQualifier == EvqSmooth)
3220 mergedQualifier = EvqCentroidIn;
3221 else if (interpolationQualifier == EvqFlat)
3222 mergedQualifier = EvqFlatIn;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003223 else
3224 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003225 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303226 else if (storageQualifier == EvqVertexOut)
3227 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003228 if (interpolationQualifier == EvqSmooth)
3229 mergedQualifier = EvqSmoothOut;
3230 else if (interpolationQualifier == EvqFlat)
3231 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003232 else
3233 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003234 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303235 else if (storageQualifier == EvqCentroidOut)
3236 {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003237 if (interpolationQualifier == EvqSmooth)
3238 mergedQualifier = EvqCentroidOut;
3239 else if (interpolationQualifier == EvqFlat)
3240 mergedQualifier = EvqFlatOut;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003241 else
3242 UNREACHABLE();
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003243 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303244 else
3245 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003246 error(interpolationLoc,
3247 "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier",
Arun Patole7e7e68d2015-05-22 12:02:25 +05303248 getInterpolationString(interpolationQualifier));
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04003249 recover();
3250
3251 mergedQualifier = storageQualifier;
3252 }
3253
3254 TPublicType type;
3255 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
3256 return type;
3257}
3258
Jamie Madillb98c3a82015-07-23 14:26:04 -04003259TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
3260 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003261{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03003262 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
3263 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003264 recover();
3265 }
3266
Arun Patole7e7e68d2015-05-22 12:02:25 +05303267 for (unsigned int i = 0; i < fieldList->size(); ++i)
3268 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003269 //
3270 // Careful not to replace already known aspects of type, like array-ness
3271 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303272 TType *type = (*fieldList)[i]->type();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003273 type->setBasicType(typeSpecifier.type);
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00003274 type->setPrimarySize(typeSpecifier.primarySize);
3275 type->setSecondarySize(typeSpecifier.secondarySize);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003276 type->setPrecision(typeSpecifier.precision);
3277 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04003278 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003279
3280 // don't allow arrays of arrays
Arun Patole7e7e68d2015-05-22 12:02:25 +05303281 if (type->isArray())
3282 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003283 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
3284 recover();
3285 }
3286 if (typeSpecifier.array)
3287 type->setArraySize(typeSpecifier.arraySize);
Arun Patole7e7e68d2015-05-22 12:02:25 +05303288 if (typeSpecifier.userDef)
3289 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003290 type->setStruct(typeSpecifier.userDef->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003291 }
3292
Arun Patole7e7e68d2015-05-22 12:02:25 +05303293 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i]))
3294 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003295 recover();
3296 }
3297 }
3298
Jamie Madill98493dd2013-07-08 14:39:03 -04003299 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003300}
3301
Jamie Madillb98c3a82015-07-23 14:26:04 -04003302TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
3303 const TSourceLoc &nameLine,
3304 const TString *structName,
3305 TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003306{
Arun Patole7e7e68d2015-05-22 12:02:25 +05303307 TStructure *structure = new TStructure(structName, fieldList);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003308 TType *structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003309
Jamie Madill9b820842015-02-12 10:40:10 -05003310 // Store a bool in the struct if we're at global scope, to allow us to
3311 // skip the local struct scoping workaround in HLSL.
Jamie Madillb960cc42015-02-12 15:33:20 +00003312 structure->setUniqueId(TSymbolTable::nextUniqueId());
Jamie Madill9b820842015-02-12 10:40:10 -05003313 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04003314
Jamie Madill98493dd2013-07-08 14:39:03 -04003315 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003316 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003317 if (reservedErrorCheck(nameLine, *structName))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003318 {
3319 recover();
3320 }
Arun Patole7e7e68d2015-05-22 12:02:25 +05303321 TVariable *userTypeDef = new TVariable(structName, *structureType, true);
3322 if (!symbolTable.declare(userTypeDef))
3323 {
Jamie Madill98493dd2013-07-08 14:39:03 -04003324 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003325 recover();
3326 }
3327 }
3328
3329 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04003330 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003331 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003332 const TField &field = *(*fieldList)[typeListIndex];
Jamie Madill98493dd2013-07-08 14:39:03 -04003333 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003334 switch (qualifier)
3335 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003336 case EvqGlobal:
3337 case EvqTemporary:
3338 break;
3339 default:
3340 error(field.line(), "invalid qualifier on struct member",
3341 getQualifierString(qualifier));
3342 recover();
3343 break;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003344 }
3345 }
3346
3347 TPublicType publicType;
3348 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04003349 publicType.userDef = structureType;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003350 exitStructDeclaration();
3351
3352 return publicType;
3353}
3354
Jamie Madillb98c3a82015-07-23 14:26:04 -04003355TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
3356 TIntermAggregate *statementList,
3357 const TSourceLoc &loc)
Olli Etuahoa3a36662015-02-17 13:46:51 +02003358{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003359 TBasicType switchType = init->getBasicType();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003360 if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
Olli Etuaho53f076f2015-02-20 10:55:14 +02003361 init->isVector())
3362 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003363 error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
3364 "switch");
Olli Etuaho53f076f2015-02-20 10:55:14 +02003365 recover();
3366 return nullptr;
3367 }
3368
Olli Etuahoac5274d2015-02-20 10:19:08 +02003369 if (statementList)
3370 {
3371 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
3372 {
3373 recover();
3374 return nullptr;
3375 }
3376 }
3377
Olli Etuahoa3a36662015-02-17 13:46:51 +02003378 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
3379 if (node == nullptr)
3380 {
3381 error(loc, "erroneous switch statement", "switch");
3382 recover();
3383 return nullptr;
3384 }
3385 return node;
3386}
3387
3388TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
3389{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003390 if (mSwitchNestingLevel == 0)
3391 {
3392 error(loc, "case labels need to be inside switch statements", "case");
3393 recover();
3394 return nullptr;
3395 }
3396 if (condition == nullptr)
3397 {
3398 error(loc, "case label must have a condition", "case");
3399 recover();
3400 return nullptr;
3401 }
3402 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
Jamie Madillb98c3a82015-07-23 14:26:04 -04003403 condition->isMatrix() || condition->isArray() || condition->isVector())
Olli Etuaho53f076f2015-02-20 10:55:14 +02003404 {
3405 error(condition->getLine(), "case label must be a scalar integer", "case");
3406 recover();
3407 }
3408 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
3409 if (conditionConst == nullptr)
3410 {
3411 error(condition->getLine(), "case label must be constant", "case");
3412 recover();
3413 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003414 TIntermCase *node = intermediate.addCase(condition, loc);
3415 if (node == nullptr)
3416 {
3417 error(loc, "erroneous case statement", "case");
3418 recover();
3419 return nullptr;
3420 }
3421 return node;
3422}
3423
3424TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
3425{
Olli Etuaho53f076f2015-02-20 10:55:14 +02003426 if (mSwitchNestingLevel == 0)
3427 {
3428 error(loc, "default labels need to be inside switch statements", "default");
3429 recover();
3430 return nullptr;
3431 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02003432 TIntermCase *node = intermediate.addCase(nullptr, loc);
3433 if (node == nullptr)
3434 {
3435 error(loc, "erroneous default statement", "default");
3436 recover();
3437 return nullptr;
3438 }
3439 return node;
3440}
3441
Jamie Madillb98c3a82015-07-23 14:26:04 -04003442TIntermTyped *TParseContext::createUnaryMath(TOperator op,
3443 TIntermTyped *child,
3444 const TSourceLoc &loc,
3445 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02003446{
3447 if (child == nullptr)
3448 {
3449 return nullptr;
3450 }
3451
3452 switch (op)
3453 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003454 case EOpLogicalNot:
3455 if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
3456 child->isVector())
3457 {
3458 return nullptr;
3459 }
3460 break;
3461 case EOpBitwiseNot:
3462 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
3463 child->isMatrix() || child->isArray())
3464 {
3465 return nullptr;
3466 }
3467 break;
3468 case EOpPostIncrement:
3469 case EOpPreIncrement:
3470 case EOpPostDecrement:
3471 case EOpPreDecrement:
3472 case EOpNegative:
3473 case EOpPositive:
3474 if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
3475 child->isArray())
3476 {
3477 return nullptr;
3478 }
3479 // Operators for built-ins are already type checked against their prototype.
3480 default:
3481 break;
Olli Etuaho69c11b52015-03-26 12:59:00 +02003482 }
3483
Olli Etuahof6c694b2015-03-26 14:50:53 +02003484 return intermediate.addUnaryMath(op, child, loc, funcReturnType);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003485}
3486
Olli Etuaho09b22472015-02-11 11:47:26 +02003487TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
3488{
Olli Etuahof6c694b2015-03-26 14:50:53 +02003489 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02003490 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02003491 {
3492 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
3493 recover();
3494 return child;
3495 }
3496 return node;
3497}
3498
Jamie Madillb98c3a82015-07-23 14:26:04 -04003499TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
3500 TIntermTyped *child,
3501 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003502{
3503 if (lValueErrorCheck(loc, GetOperatorString(op), child))
3504 recover();
3505 return addUnaryMath(op, child, loc);
3506}
3507
Jamie Madillb98c3a82015-07-23 14:26:04 -04003508bool TParseContext::binaryOpCommonCheck(TOperator op,
3509 TIntermTyped *left,
3510 TIntermTyped *right,
3511 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003512{
3513 if (left->isArray() || right->isArray())
3514 {
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003515 if (mShaderVersion < 300)
Olli Etuahoe79904c2015-03-18 16:56:42 +02003516 {
3517 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3518 return false;
3519 }
3520
3521 if (left->isArray() != right->isArray())
3522 {
3523 error(loc, "array / non-array mismatch", GetOperatorString(op));
3524 return false;
3525 }
3526
3527 switch (op)
3528 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003529 case EOpEqual:
3530 case EOpNotEqual:
3531 case EOpAssign:
3532 case EOpInitialize:
3533 break;
3534 default:
3535 error(loc, "Invalid operation for arrays", GetOperatorString(op));
3536 return false;
Olli Etuahoe79904c2015-03-18 16:56:42 +02003537 }
Olli Etuaho376f1b52015-04-13 13:23:41 +03003538 // At this point, size of implicitly sized arrays should be resolved.
Olli Etuahoe79904c2015-03-18 16:56:42 +02003539 if (left->getArraySize() != right->getArraySize())
3540 {
3541 error(loc, "array size mismatch", GetOperatorString(op));
3542 return false;
3543 }
Olli Etuahod6b14282015-03-17 14:31:35 +02003544 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003545
3546 // Check ops which require integer / ivec parameters
3547 bool isBitShift = false;
3548 switch (op)
3549 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003550 case EOpBitShiftLeft:
3551 case EOpBitShiftRight:
3552 case EOpBitShiftLeftAssign:
3553 case EOpBitShiftRightAssign:
3554 // Unsigned can be bit-shifted by signed and vice versa, but we need to
3555 // check that the basic type is an integer type.
3556 isBitShift = true;
3557 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
3558 {
3559 return false;
3560 }
3561 break;
3562 case EOpBitwiseAnd:
3563 case EOpBitwiseXor:
3564 case EOpBitwiseOr:
3565 case EOpBitwiseAndAssign:
3566 case EOpBitwiseXorAssign:
3567 case EOpBitwiseOrAssign:
3568 // It is enough to check the type of only one operand, since later it
3569 // is checked that the operand types match.
3570 if (!IsInteger(left->getBasicType()))
3571 {
3572 return false;
3573 }
3574 break;
3575 default:
3576 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003577 }
3578
3579 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
3580 // So the basic type should usually match.
3581 if (!isBitShift && left->getBasicType() != right->getBasicType())
3582 {
3583 return false;
3584 }
3585
Olli Etuaho9dd217b2015-03-20 14:24:31 +02003586 // Check that type sizes match exactly on ops that require that.
Olli Etuahoff699002015-03-23 14:38:42 +02003587 // Also check restrictions for structs that contain arrays or samplers.
Jamie Madillb98c3a82015-07-23 14:26:04 -04003588 switch (op)
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003589 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003590 case EOpAssign:
3591 case EOpInitialize:
3592 case EOpEqual:
3593 case EOpNotEqual:
3594 // ESSL 1.00 sections 5.7, 5.8, 5.9
3595 if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
3596 {
3597 error(loc, "undefined operation for structs containing arrays",
3598 GetOperatorString(op));
3599 return false;
3600 }
3601 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
3602 // we interpret the spec so that this extends to structs containing samplers,
3603 // similarly to ESSL 1.00 spec.
3604 if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
3605 left->getType().isStructureContainingSamplers())
3606 {
3607 error(loc, "undefined operation for structs containing samplers",
3608 GetOperatorString(op));
3609 return false;
3610 }
3611 case EOpLessThan:
3612 case EOpGreaterThan:
3613 case EOpLessThanEqual:
3614 case EOpGreaterThanEqual:
3615 if ((left->getNominalSize() != right->getNominalSize()) ||
3616 (left->getSecondarySize() != right->getSecondarySize()))
3617 {
3618 return false;
3619 }
3620 default:
3621 break;
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003622 }
3623
Olli Etuahod6b14282015-03-17 14:31:35 +02003624 return true;
3625}
3626
Jamie Madillb98c3a82015-07-23 14:26:04 -04003627TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
3628 TIntermTyped *left,
3629 TIntermTyped *right,
3630 const TSourceLoc &loc)
Olli Etuahofc1806e2015-03-17 13:03:11 +02003631{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003632 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003633 return nullptr;
3634
Olli Etuahofc1806e2015-03-17 13:03:11 +02003635 switch (op)
3636 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003637 case EOpEqual:
3638 case EOpNotEqual:
3639 break;
3640 case EOpLessThan:
3641 case EOpGreaterThan:
3642 case EOpLessThanEqual:
3643 case EOpGreaterThanEqual:
3644 ASSERT(!left->isArray() && !right->isArray());
3645 if (left->isMatrix() || left->isVector() || left->getBasicType() == EbtStruct)
3646 {
3647 return nullptr;
3648 }
3649 break;
3650 case EOpLogicalOr:
3651 case EOpLogicalXor:
3652 case EOpLogicalAnd:
3653 ASSERT(!left->isArray() && !right->isArray());
3654 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
3655 {
3656 return nullptr;
3657 }
3658 break;
3659 case EOpAdd:
3660 case EOpSub:
3661 case EOpDiv:
3662 case EOpMul:
3663 ASSERT(!left->isArray() && !right->isArray());
3664 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
3665 {
3666 return nullptr;
3667 }
3668 break;
3669 case EOpIMod:
3670 ASSERT(!left->isArray() && !right->isArray());
3671 // Note that this is only for the % operator, not for mod()
3672 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool ||
3673 left->getBasicType() == EbtFloat)
3674 {
3675 return nullptr;
3676 }
3677 break;
3678 // Note that for bitwise ops, type checking is done in promote() to
3679 // share code between ops and compound assignment
3680 default:
3681 break;
Olli Etuahofc1806e2015-03-17 13:03:11 +02003682 }
3683
Olli Etuahofc1806e2015-03-17 13:03:11 +02003684 return intermediate.addBinaryMath(op, left, right, loc);
3685}
3686
Jamie Madillb98c3a82015-07-23 14:26:04 -04003687TIntermTyped *TParseContext::addBinaryMath(TOperator op,
3688 TIntermTyped *left,
3689 TIntermTyped *right,
3690 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003691{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003692 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003693 if (node == 0)
3694 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003695 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3696 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003697 recover();
3698 return left;
3699 }
3700 return node;
3701}
3702
Jamie Madillb98c3a82015-07-23 14:26:04 -04003703TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
3704 TIntermTyped *left,
3705 TIntermTyped *right,
3706 const TSourceLoc &loc)
Olli Etuaho09b22472015-02-11 11:47:26 +02003707{
Olli Etuahofc1806e2015-03-17 13:03:11 +02003708 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003709 if (node == 0)
3710 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003711 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
3712 right->getCompleteString());
Olli Etuaho09b22472015-02-11 11:47:26 +02003713 recover();
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003714 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuaho09b22472015-02-11 11:47:26 +02003715 unionArray->setBConst(false);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003716 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
3717 loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02003718 }
3719 return node;
3720}
3721
Jamie Madillb98c3a82015-07-23 14:26:04 -04003722TIntermTyped *TParseContext::createAssign(TOperator op,
3723 TIntermTyped *left,
3724 TIntermTyped *right,
3725 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003726{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02003727 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02003728 {
3729 return intermediate.addAssign(op, left, right, loc);
3730 }
3731 return nullptr;
3732}
3733
Jamie Madillb98c3a82015-07-23 14:26:04 -04003734TIntermTyped *TParseContext::addAssign(TOperator op,
3735 TIntermTyped *left,
3736 TIntermTyped *right,
3737 const TSourceLoc &loc)
Olli Etuahod6b14282015-03-17 14:31:35 +02003738{
3739 TIntermTyped *node = createAssign(op, left, right, loc);
3740 if (node == nullptr)
3741 {
3742 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
3743 recover();
3744 return left;
3745 }
3746 return node;
3747}
3748
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02003749TIntermTyped *TParseContext::addComma(TIntermTyped *left,
3750 TIntermTyped *right,
3751 const TSourceLoc &loc)
3752{
Olli Etuaho15200042015-11-04 16:56:31 +02003753 return intermediate.addComma(left, right, loc, mShaderVersion);
Olli Etuaho0b2d2dc2015-11-04 16:35:32 +02003754}
3755
Olli Etuaho49300862015-02-20 14:54:49 +02003756TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
3757{
3758 switch (op)
3759 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003760 case EOpContinue:
3761 if (mLoopNestingLevel <= 0)
3762 {
3763 error(loc, "continue statement only allowed in loops", "");
3764 recover();
3765 }
3766 break;
3767 case EOpBreak:
3768 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
3769 {
3770 error(loc, "break statement only allowed in loops and switch statements", "");
3771 recover();
3772 }
3773 break;
3774 case EOpReturn:
3775 if (mCurrentFunctionType->getBasicType() != EbtVoid)
3776 {
3777 error(loc, "non-void function must return a value", "return");
3778 recover();
3779 }
3780 break;
3781 default:
3782 // No checks for discard
3783 break;
Olli Etuaho49300862015-02-20 14:54:49 +02003784 }
3785 return intermediate.addBranch(op, loc);
3786}
3787
Jamie Madillb98c3a82015-07-23 14:26:04 -04003788TIntermBranch *TParseContext::addBranch(TOperator op,
3789 TIntermTyped *returnValue,
3790 const TSourceLoc &loc)
Olli Etuaho49300862015-02-20 14:54:49 +02003791{
3792 ASSERT(op == EOpReturn);
3793 mFunctionReturnsValue = true;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003794 if (mCurrentFunctionType->getBasicType() == EbtVoid)
Olli Etuaho49300862015-02-20 14:54:49 +02003795 {
3796 error(loc, "void function cannot return a value", "return");
3797 recover();
3798 }
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003799 else if (*mCurrentFunctionType != returnValue->getType())
Olli Etuaho49300862015-02-20 14:54:49 +02003800 {
3801 error(loc, "function return is not matching type:", "return");
3802 recover();
3803 }
3804 return intermediate.addBranch(op, returnValue, loc);
3805}
3806
Jamie Madillb98c3a82015-07-23 14:26:04 -04003807TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
3808 TIntermNode *paramNode,
3809 TIntermNode *thisNode,
3810 const TSourceLoc &loc,
3811 bool *fatalError)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003812{
Jamie Madillb98c3a82015-07-23 14:26:04 -04003813 *fatalError = false;
3814 TOperator op = fnCall->getBuiltInOp();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003815 TIntermTyped *callNode = nullptr;
3816
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003817 if (thisNode != nullptr)
3818 {
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003819 TConstantUnion *unionArray = new TConstantUnion[1];
Jamie Madillb98c3a82015-07-23 14:26:04 -04003820 int arraySize = 0;
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003821 TIntermTyped *typedThis = thisNode->getAsTyped();
3822 if (fnCall->getName() != "length")
3823 {
3824 error(loc, "invalid method", fnCall->getName().c_str());
3825 recover();
3826 }
3827 else if (paramNode != nullptr)
3828 {
3829 error(loc, "method takes no parameters", "length");
3830 recover();
3831 }
3832 else if (typedThis == nullptr || !typedThis->isArray())
3833 {
3834 error(loc, "length can only be called on arrays", "length");
3835 recover();
3836 }
3837 else
3838 {
Olli Etuaho96e67382015-04-23 14:27:02 +03003839 arraySize = typedThis->getArraySize();
Olli Etuaho39282e12015-04-23 15:41:48 +03003840 if (typedThis->getAsSymbolNode() == nullptr)
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003841 {
Olli Etuaho39282e12015-04-23 15:41:48 +03003842 // This code path can be hit with expressions like these:
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003843 // (a = b).length()
Olli Etuaho39282e12015-04-23 15:41:48 +03003844 // (func()).length()
3845 // (int[3](0, 1, 2)).length()
Jamie Madillb98c3a82015-07-23 14:26:04 -04003846 // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
3847 // expression.
3848 // It allows "An array name with the length method applied" in contrast to GLSL 4.4
3849 // spec section 5.9 which allows "An array, vector or matrix expression with the
3850 // length method applied".
3851 error(loc, "length can only be called on array names, not on array expressions",
3852 "length");
Olli Etuaho39282e12015-04-23 15:41:48 +03003853 recover();
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003854 }
3855 }
Olli Etuaho96e67382015-04-23 14:27:02 +03003856 unionArray->setIConst(arraySize);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003857 callNode =
3858 intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003859 }
3860 else if (op != EOpNull)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003861 {
3862 //
3863 // Then this should be a constructor.
3864 // Don't go through the symbol table for constructors.
3865 // Their parameters will be verified algorithmically.
3866 //
3867 TType type(EbtVoid, EbpUndefined); // use this to get the type back
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003868 if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type))
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003869 {
3870 //
3871 // It's a constructor, of type 'type'.
3872 //
Olli Etuahoffe6edf2015-04-13 17:32:03 +03003873 callNode = addConstructor(paramNode, &type, op, fnCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003874 }
Olli Etuaho72ba85b2015-03-04 14:23:26 +02003875
3876 if (callNode == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003877 {
3878 recover();
3879 callNode = intermediate.setAggregateOperator(nullptr, op, loc);
3880 }
3881 callNode->setType(type);
3882 }
3883 else
3884 {
3885 //
3886 // Not a constructor. Find it in the symbol table.
3887 //
Arun Patole7e7e68d2015-05-22 12:02:25 +05303888 const TFunction *fnCandidate;
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003889 bool builtIn;
Jamie Madill6e06b1f2015-05-14 10:01:17 -04003890 fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003891 if (fnCandidate)
3892 {
3893 //
3894 // A declared function.
3895 //
3896 if (builtIn && !fnCandidate->getExtension().empty() &&
3897 extensionErrorCheck(loc, fnCandidate->getExtension()))
3898 {
3899 recover();
3900 }
3901 op = fnCandidate->getBuiltInOp();
3902 if (builtIn && op != EOpNull)
3903 {
3904 //
3905 // A function call mapped to a built-in operation.
3906 //
3907 if (fnCandidate->getParamCount() == 1)
3908 {
3909 //
3910 // Treat it like a built-in unary operator.
3911 //
Jamie Madillb98c3a82015-07-23 14:26:04 -04003912 callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
3913 &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003914 if (callNode == nullptr)
3915 {
3916 std::stringstream extraInfoStream;
Jamie Madillb98c3a82015-07-23 14:26:04 -04003917 extraInfoStream
3918 << "built in unary operator function. Type: "
3919 << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003920 std::string extraInfo = extraInfoStream.str();
Jamie Madillb98c3a82015-07-23 14:26:04 -04003921 error(paramNode->getLine(), " wrong operand type", "Internal Error",
3922 extraInfo.c_str());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003923 *fatalError = true;
3924 return nullptr;
3925 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003926 }
3927 else
3928 {
Jamie Madillb98c3a82015-07-23 14:26:04 -04003929 TIntermAggregate *aggregate =
3930 intermediate.setAggregateOperator(paramNode, op, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003931 aggregate->setType(fnCandidate->getReturnType());
3932 aggregate->setPrecisionFromChildren();
Olli Etuahob1edc4f2015-11-02 17:20:03 +02003933 if (aggregate->areChildrenConstQualified())
3934 {
3935 aggregate->getTypePointer()->setQualifier(EvqConst);
3936 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003937
3938 // Some built-in functions have out parameters too.
3939 functionCallLValueErrorCheck(fnCandidate, aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303940
3941 // See if we can constant fold a built-in.
Olli Etuahob43846e2015-06-02 18:18:57 +03003942 TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
Arun Patole274f0702015-05-05 13:33:30 +05303943 if (foldedNode)
3944 {
Arun Patole274f0702015-05-05 13:33:30 +05303945 callNode = foldedNode;
3946 }
Olli Etuahob43846e2015-06-02 18:18:57 +03003947 else
3948 {
3949 callNode = aggregate;
3950 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003951 }
3952 }
3953 else
3954 {
3955 // This is a real function call
3956
Jamie Madillb98c3a82015-07-23 14:26:04 -04003957 TIntermAggregate *aggregate =
3958 intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003959 aggregate->setType(fnCandidate->getReturnType());
3960
Jamie Madillb98c3a82015-07-23 14:26:04 -04003961 // this is how we know whether the given function is a builtIn function or a user
3962 // defined function
3963 // if builtIn == false, it's a userDefined -> could be an overloaded
3964 // builtIn function also
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003965 // if builtIn == true, it's definitely a builtIn function with EOpNull
3966 if (!builtIn)
3967 aggregate->setUserDefined();
3968 aggregate->setName(fnCandidate->getMangledName());
Corentin Wallez71d147f2015-02-11 11:15:24 -08003969 aggregate->setFunctionId(fnCandidate->getUniqueId());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003970
3971 // This needs to happen after the name is set
3972 if (builtIn)
3973 aggregate->setBuiltInFunctionPrecision();
3974
3975 callNode = aggregate;
3976
3977 functionCallLValueErrorCheck(fnCandidate, aggregate);
3978 }
3979 }
3980 else
3981 {
3982 // error message was put out by findFunction()
3983 // Put on a dummy node for error recovery
Jamie Madill6ba6ead2015-05-04 14:21:21 -04003984 TConstantUnion *unionArray = new TConstantUnion[1];
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003985 unionArray->setFConst(0.0f);
Jamie Madillb98c3a82015-07-23 14:26:04 -04003986 callNode = intermediate.addConstantUnion(unionArray,
3987 TType(EbtFloat, EbpUndefined, EvqConst), loc);
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003988 recover();
3989 }
3990 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003991 return callNode;
3992}
3993
Jamie Madillb98c3a82015-07-23 14:26:04 -04003994TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
3995 TIntermTyped *trueBlock,
3996 TIntermTyped *falseBlock,
Olli Etuaho52901742015-04-15 13:42:45 +03003997 const TSourceLoc &loc)
3998{
3999 if (boolErrorCheck(loc, cond))
4000 recover();
4001
4002 if (trueBlock->getType() != falseBlock->getType())
4003 {
4004 binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
4005 recover();
4006 return falseBlock;
4007 }
Olli Etuahoa2d53032015-04-15 14:14:44 +03004008 // ESSL1 sections 5.2 and 5.7:
4009 // ESSL3 section 5.7:
4010 // Ternary operator is not among the operators allowed for structures/arrays.
4011 if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
4012 {
4013 error(loc, "ternary operator is not allowed for structures or arrays", ":");
4014 recover();
4015 return falseBlock;
4016 }
Olli Etuaho52901742015-04-15 13:42:45 +03004017 return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
4018}
Olli Etuaho49300862015-02-20 14:54:49 +02004019
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00004020//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004021// Parse an array of strings using yyparse.
4022//
4023// Returns 0 for success.
4024//
Jamie Madillb98c3a82015-07-23 14:26:04 -04004025int PaParseStrings(size_t count,
4026 const char *const string[],
4027 const int length[],
Arun Patole7e7e68d2015-05-22 12:02:25 +05304028 TParseContext *context)
4029{
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004030 if ((count == 0) || (string == NULL))
4031 return 1;
4032
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004033 if (glslang_initialize(context))
4034 return 1;
4035
alokp@chromium.org408c45e2012-04-05 15:54:43 +00004036 int error = glslang_scan(count, string, length, context);
4037 if (!error)
4038 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004039
alokp@chromium.org73bc2982012-06-19 18:48:05 +00004040 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00004041
alokp@chromium.org6b495712012-06-29 00:06:58 +00004042 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00004043}