blob: b543ea2d5baf0ff40da5bb330cdab2e10d81217f [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madill6b9cb252013-10-17 10:45:47 -04007#include "compiler/translator/ParseContext.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009#include <stdarg.h>
apatrick@chromium.org8187fa82010-06-15 22:09:28 +000010#include <stdio.h>
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011
daniel@transgaming.comb401a922012-10-26 18:58:24 +000012#include "compiler/preprocessor/SourceLocation.h"
Olli Etuahoac5274d2015-02-20 10:19:08 +020013#include "compiler/translator/glslang.h"
14#include "compiler/translator/ValidateSwitch.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000015
alokp@chromium.org8b851c62012-06-15 16:25:11 +000016///////////////////////////////////////////////////////////////////////
17//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018// Sub- vector and matrix fields
19//
20////////////////////////////////////////////////////////////////////////
21
22//
23// Look at a '.' field selector string and change it into offsets
24// for a vector.
25//
Jamie Madill075edd82013-07-08 13:30:19 -040026bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000028 fields.num = (int) compString.size();
29 if (fields.num > 4) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000030 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000031 return false;
32 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000034 enum {
35 exyzw,
36 ergba,
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000037 estpq
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000038 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000039
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000040 for (int i = 0; i < fields.num; ++i) {
41 switch (compString[i]) {
42 case 'x':
43 fields.offsets[i] = 0;
44 fieldSet[i] = exyzw;
45 break;
46 case 'r':
47 fields.offsets[i] = 0;
48 fieldSet[i] = ergba;
49 break;
50 case 's':
51 fields.offsets[i] = 0;
52 fieldSet[i] = estpq;
53 break;
54 case 'y':
55 fields.offsets[i] = 1;
56 fieldSet[i] = exyzw;
57 break;
58 case 'g':
59 fields.offsets[i] = 1;
60 fieldSet[i] = ergba;
61 break;
62 case 't':
63 fields.offsets[i] = 1;
64 fieldSet[i] = estpq;
65 break;
66 case 'z':
67 fields.offsets[i] = 2;
68 fieldSet[i] = exyzw;
69 break;
70 case 'b':
71 fields.offsets[i] = 2;
72 fieldSet[i] = ergba;
73 break;
74 case 'p':
75 fields.offsets[i] = 2;
76 fieldSet[i] = estpq;
77 break;
78
79 case 'w':
80 fields.offsets[i] = 3;
81 fieldSet[i] = exyzw;
82 break;
83 case 'a':
84 fields.offsets[i] = 3;
85 fieldSet[i] = ergba;
86 break;
87 case 'q':
88 fields.offsets[i] = 3;
89 fieldSet[i] = estpq;
90 break;
91 default:
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000092 error(line, "illegal vector field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000093 return false;
94 }
95 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000097 for (int i = 0; i < fields.num; ++i) {
98 if (fields.offsets[i] >= vecSize) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000099 error(line, "vector field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000100 return false;
101 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000103 if (i > 0) {
104 if (fieldSet[i] != fieldSet[i-1]) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000105 error(line, "illegal - vector component fields not from the same set", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000106 return false;
107 }
108 }
109 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000111 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112}
113
114
115//
116// Look at a '.' field selector string and change it into offsets
117// for a matrix.
118//
Jamie Madill075edd82013-07-08 13:30:19 -0400119bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000121 fields.wholeRow = false;
122 fields.wholeCol = false;
123 fields.row = -1;
124 fields.col = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000126 if (compString.size() != 2) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000127 error(line, "illegal length of matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000128 return false;
129 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000131 if (compString[0] == '_') {
132 if (compString[1] < '0' || compString[1] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000133 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000134 return false;
135 }
136 fields.wholeCol = true;
137 fields.col = compString[1] - '0';
138 } else if (compString[1] == '_') {
139 if (compString[0] < '0' || compString[0] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000140 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000141 return false;
142 }
143 fields.wholeRow = true;
144 fields.row = compString[0] - '0';
145 } else {
146 if (compString[0] < '0' || compString[0] > '3' ||
147 compString[1] < '0' || compString[1] > '3') {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000148 error(line, "illegal matrix field selection", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000149 return false;
150 }
151 fields.row = compString[0] - '0';
152 fields.col = compString[1] - '0';
153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000155 if (fields.row >= matRows || fields.col >= matCols) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000156 error(line, "matrix field selection out of range", compString.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000157 return false;
158 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000160 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161}
162
163///////////////////////////////////////////////////////////////////////
164//
165// Errors
166//
167////////////////////////////////////////////////////////////////////////
168
169//
170// Track whether errors have occurred.
171//
172void TParseContext::recover()
173{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174}
175
176//
177// Used by flex/bison to output all syntax and parsing errors.
178//
Jamie Madill075edd82013-07-08 13:30:19 -0400179void TParseContext::error(const TSourceLoc& loc,
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000180 const char* reason, const char* token,
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000181 const char* extraInfo)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182{
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000183 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400184 srcLoc.file = loc.first_file;
185 srcLoc.line = loc.first_line;
Shannon Woods7f2d7942013-11-19 15:07:58 -0500186 diagnostics.writeInfo(pp::Diagnostics::PP_ERROR,
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000187 srcLoc, reason, token, extraInfo);
alokp@chromium.orgff42c632010-05-10 15:14:30 +0000188
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
Jamie Madill075edd82013-07-08 13:30:19 -0400191void TParseContext::warning(const TSourceLoc& loc,
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000192 const char* reason, const char* token,
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000193 const char* extraInfo) {
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000194 pp::SourceLocation srcLoc;
Jamie Madill075edd82013-07-08 13:30:19 -0400195 srcLoc.file = loc.first_file;
196 srcLoc.line = loc.first_line;
Shannon Woods7f2d7942013-11-19 15:07:58 -0500197 diagnostics.writeInfo(pp::Diagnostics::PP_WARNING,
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000198 srcLoc, reason, token, extraInfo);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +0000199}
200
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000201void TParseContext::trace(const char* str)
202{
203 diagnostics.writeDebug(str);
204}
205
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206//
207// Same error message for all places assignments don't work.
208//
Jamie Madill075edd82013-07-08 13:30:19 -0400209void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000211 std::stringstream extraInfoStream;
212 extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
213 std::string extraInfo = extraInfoStream.str();
214 error(line, "", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215}
216
217//
218// Same error message for all places unary operations don't work.
219//
Jamie Madill075edd82013-07-08 13:30:19 -0400220void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000222 std::stringstream extraInfoStream;
223 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
224 << " (or there is no acceptable conversion)";
225 std::string extraInfo = extraInfoStream.str();
226 error(line, " wrong operand type", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227}
228
229//
230// Same error message for all binary operations don't work.
231//
Jamie Madill075edd82013-07-08 13:30:19 -0400232void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233{
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000234 std::stringstream extraInfoStream;
235 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
236 << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
237 std::string extraInfo = extraInfoStream.str();
238 error(line, " wrong operand types ", op, extraInfo.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239}
240
Jamie Madill075edd82013-07-08 13:30:19 -0400241bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000242 if (!checksPrecisionErrors)
243 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000244 switch( type ){
245 case EbtFloat:
246 if( precision == EbpUndefined ){
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000247 error( line, "No precision specified for (float)", "" );
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000248 return true;
249 }
250 break;
251 case EbtInt:
252 if( precision == EbpUndefined ){
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000253 error( line, "No precision specified (int)", "" );
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000254 return true;
255 }
256 break;
daniel@transgaming.com0eb64c32011-03-15 18:23:51 +0000257 default:
258 return false;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000259 }
260 return false;
261}
262
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000263//
264// Both test and if necessary, spit out an error, to see if the node is really
265// an l-value that can be operated on this way.
266//
267// Returns true if the was an error.
268//
Jamie Madill075edd82013-07-08 13:30:19 -0400269bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000271 TIntermSymbol* symNode = node->getAsSymbolNode();
272 TIntermBinary* binaryNode = node->getAsBinaryNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000274 if (binaryNode) {
275 bool errorReturn;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000277 switch(binaryNode->getOp()) {
278 case EOpIndexDirect:
279 case EOpIndexIndirect:
280 case EOpIndexDirectStruct:
shannonwoods@chromium.org4430b0d2013-05-30 00:12:34 +0000281 case EOpIndexDirectInterfaceBlock:
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000282 return lValueErrorCheck(line, op, binaryNode->getLeft());
283 case EOpVectorSwizzle:
284 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
285 if (!errorReturn) {
286 int offset[4] = {0,0,0,0};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000288 TIntermTyped* rightNode = binaryNode->getRight();
289 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700290
291 for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
292 p != aggrNode->getSequence()->end(); p++) {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000293 int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700294 offset[value]++;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000295 if (offset[value] > 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000296 error(line, " l-value of swizzle cannot have duplicate components", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000298 return true;
299 }
300 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700301 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000303 return errorReturn;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700304 default:
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000305 break;
306 }
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000307 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000309 return true;
310 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311
312
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000313 const char* symbol = 0;
314 if (symNode != 0)
315 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000317 const char* message = 0;
318 switch (node->getQualifier()) {
319 case EvqConst: message = "can't modify a const"; break;
320 case EvqConstReadOnly: message = "can't modify a const"; break;
321 case EvqAttribute: message = "can't modify an attribute"; break;
Jamie Madill19571812013-08-12 15:26:34 -0700322 case EvqFragmentIn: message = "can't modify an input"; break;
323 case EvqVertexIn: message = "can't modify an input"; break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000324 case EvqUniform: message = "can't modify a uniform"; break;
325 case EvqVaryingIn: message = "can't modify a varying"; break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000326 case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
327 case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
328 case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
329 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000331 //
332 // Type that can't be written to?
333 //
Nicolas Capens344e7142013-06-24 15:39:21 -0400334 if (node->getBasicType() == EbtVoid) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000335 message = "can't modify void";
Nicolas Capens344e7142013-06-24 15:39:21 -0400336 }
337 if (IsSampler(node->getBasicType())) {
338 message = "can't modify a sampler";
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000339 }
340 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000342 if (message == 0 && binaryNode == 0 && symNode == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000343 error(line, " l-value required", op);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000345 return true;
346 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347
348
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000349 //
350 // Everything else is okay, no error.
351 //
352 if (message == 0)
353 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000355 //
356 // If we get here, we have an error and a message.
357 //
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000358 if (symNode) {
359 std::stringstream extraInfoStream;
360 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
361 std::string extraInfo = extraInfoStream.str();
362 error(line, " l-value required", op, extraInfo.c_str());
363 }
364 else {
365 std::stringstream extraInfoStream;
366 extraInfoStream << "(" << message << ")";
367 std::string extraInfo = extraInfoStream.str();
368 error(line, " l-value required", op, extraInfo.c_str());
369 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000371 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372}
373
374//
375// Both test, and if necessary spit out an error, to see if the node is really
376// a constant.
377//
378// Returns true if the was an error.
379//
380bool TParseContext::constErrorCheck(TIntermTyped* node)
381{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000382 if (node->getQualifier() == EvqConst)
383 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000385 error(node->getLine(), "constant expression required", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000387 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388}
389
390//
391// Both test, and if necessary spit out an error, to see if the node is really
392// an integer.
393//
394// Returns true if the was an error.
395//
396bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
397{
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000398 if (node->isScalarInt())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000399 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000401 error(node->getLine(), "integer expression required", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000403 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000404}
405
406//
407// Both test, and if necessary spit out an error, to see if we are currently
408// globally scoped.
409//
410// Returns true if the was an error.
411//
Jamie Madill075edd82013-07-08 13:30:19 -0400412bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000414 if (global)
415 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000417 error(line, "only allowed at global scope", token);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000419 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420}
421
422//
423// For now, keep it simple: if it starts "gl_", it's reserved, independent
424// of scope. Except, if the symbol table is at the built-in push-level,
425// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000426// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
427// webgl shader.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428//
429// Returns true if there was an error.
430//
Jamie Madill075edd82013-07-08 13:30:19 -0400431bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432{
alokp@chromium.org613ef312010-07-21 18:54:22 +0000433 static const char* reservedErrMsg = "reserved built-in name";
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000434 if (!symbolTable.atBuiltInLevel()) {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000435 if (identifier.compare(0, 3, "gl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000436 error(line, reservedErrMsg, "gl_");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000437 return true;
438 }
Jamie Madill5508f392014-02-20 13:31:36 -0500439 if (IsWebGLBasedSpec(shaderSpec)) {
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000440 if (identifier.compare(0, 6, "webgl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000441 error(line, reservedErrMsg, "webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000442 return true;
443 }
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +0000444 if (identifier.compare(0, 7, "_webgl_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000445 error(line, reservedErrMsg, "_webgl_");
alokp@chromium.org613ef312010-07-21 18:54:22 +0000446 return true;
447 }
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000448 if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000449 error(line, reservedErrMsg, "css_");
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000450 return true;
451 }
alokp@chromium.org613ef312010-07-21 18:54:22 +0000452 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000453 if (identifier.find("__") != TString::npos) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000454 error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
daniel@transgaming.combeadd5d2012-04-12 02:35:31 +0000455 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000456 }
457 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000459 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460}
461
462//
463// Make sure there is enough data provided to the constructor to build
464// something of the type of the constructor. Also returns the type of
465// the constructor.
466//
467// Returns true if there was an error in construction.
468//
Jamie Madill075edd82013-07-08 13:30:19 -0400469bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000471 *type = function.getReturnType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000473 bool constructingMatrix = false;
474 switch(op) {
475 case EOpConstructMat2:
476 case EOpConstructMat3:
477 case EOpConstructMat4:
478 constructingMatrix = true;
479 break;
480 default:
481 break;
482 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000484 //
485 // Note: It's okay to have too many components available, but not okay to have unused
486 // arguments. 'full' will go to true when enough args have been seen. If we loop
487 // again, there is an extra argument, so 'overfull' will become true.
488 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489
Jamie Madill94bf7f22013-07-08 13:31:15 -0400490 size_t size = 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000491 bool constType = true;
492 bool full = false;
493 bool overFull = false;
494 bool matrixInMatrix = false;
495 bool arrayArg = false;
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000496 for (size_t i = 0; i < function.getParamCount(); ++i) {
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000497 const TParameter& param = function.getParam(i);
498 size += param.type->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000499
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000500 if (constructingMatrix && param.type->isMatrix())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000501 matrixInMatrix = true;
502 if (full)
503 overFull = true;
504 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
505 full = true;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000506 if (param.type->getQualifier() != EvqConst)
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000507 constType = false;
alokp@chromium.orgb19403a2010-09-08 17:56:26 +0000508 if (param.type->isArray())
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000509 arrayArg = true;
510 }
511
512 if (constType)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000513 type->setQualifier(EvqConst);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514
shannon.woods@transgaming.com18bd2ec2013-02-28 23:19:46 +0000515 if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000516 error(line, "array constructor needs one argument per array element", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000517 return true;
518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000520 if (arrayArg && op != EOpConstructStruct) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000521 error(line, "constructing from a non-dereferenced array", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000522 return true;
523 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000525 if (matrixInMatrix && !type->isArray()) {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000526 if (function.getParamCount() != 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000527 error(line, "constructing matrix from matrix can only take one argument", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000528 return true;
529 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000530 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000532 if (overFull) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000533 error(line, "too many arguments", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000534 return true;
535 }
536
Brendan Longeaa84062013-12-08 18:26:50 +0100537 if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000538 error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000539 return true;
540 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541
daniel@transgaming.com67d72522011-11-29 17:23:51 +0000542 if (!type->isMatrix() || !matrixInMatrix) {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000543 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
544 (op == EOpConstructStruct && size < type->getObjectSize())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000545 error(line, "not enough data provided for construction", "constructor");
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000546 return true;
547 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000548 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549
daniel@transgaming.com0b53fc02011-03-09 15:12:12 +0000550 TIntermTyped *typed = node ? node->getAsTyped() : 0;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000551 if (typed == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000552 error(line, "constructor argument does not have a type", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000553 return true;
554 }
555 if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000556 error(line, "cannot convert a sampler", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000557 return true;
558 }
559 if (typed->getBasicType() == EbtVoid) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000560 error(line, "cannot convert a void", "constructor");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000561 return true;
562 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000563
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000564 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565}
566
567// This function checks to see if a void variable has been declared and raise an error message for such a case
568//
569// returns true in case of an error
570//
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300571bool TParseContext::voidErrorCheck(const TSourceLoc &line, const TString &identifier, const TBasicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300573 if (type == EbtVoid)
574 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000575 error(line, "illegal use of type 'void'", identifier.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000576 return true;
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +0300577 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000579 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580}
581
582// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
583//
584// returns true in case of an error
585//
Jamie Madill075edd82013-07-08 13:30:19 -0400586bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000587{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000588 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000589 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000590 return true;
591 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000592
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000593 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594}
595
596// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
597//
598// returns true in case of an error
599//
Jamie Madill075edd82013-07-08 13:30:19 -0400600bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601{
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000602 if (pType.type != EbtBool || pType.isAggregate()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000603 error(line, "boolean expression expected", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000604 return true;
605 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000607 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608}
609
Jamie Madill075edd82013-07-08 13:30:19 -0400610bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000612 if (pType.type == EbtStruct) {
613 if (containsSampler(*pType.userDef)) {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000614 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000615
616 return true;
617 }
618
619 return false;
620 } else if (IsSampler(pType.type)) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000621 error(line, reason, getBasicString(pType.type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000623 return true;
624 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000625
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000626 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000627}
628
Jamie Madill075edd82013-07-08 13:30:19 -0400629bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630{
Jamie Madillb120eac2013-06-12 14:08:13 -0400631 switch (pType.qualifier)
632 {
633 case EvqVaryingIn:
634 case EvqVaryingOut:
635 case EvqAttribute:
Jamie Madill19571812013-08-12 15:26:34 -0700636 case EvqVertexIn:
637 case EvqFragmentOut:
Jamie Madillb120eac2013-06-12 14:08:13 -0400638 if (pType.type == EbtStruct)
639 {
640 error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
641 return true;
642 }
Jamie Madill10567262014-04-17 16:40:00 -0400643
644 default: break;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000645 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000647 if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
648 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000650 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651}
652
Jamie Madill075edd82013-07-08 13:30:19 -0400653bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
Jamie Madill0bd18df2013-06-20 11:55:52 -0400654{
655 if (pType.layoutQualifier.location != -1)
656 {
657 error(line, "location must only be specified for a single input or output variable", "location");
658 return true;
659 }
660
661 return false;
662}
663
Jamie Madill075edd82013-07-08 13:30:19 -0400664bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000666 if ((qualifier == EvqOut || qualifier == EvqInOut) &&
667 type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000668 error(line, "samplers cannot be output parameters", type.getBasicString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000669 return true;
670 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000671
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000672 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673}
674
675bool TParseContext::containsSampler(TType& type)
676{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000677 if (IsSampler(type.getBasicType()))
678 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679
Jamie Madill98493dd2013-07-08 14:39:03 -0400680 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
681 const TFieldList& fields = type.getStruct()->fields();
682 for (unsigned int i = 0; i < fields.size(); ++i) {
683 if (containsSampler(*fields[i]->type()))
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000684 return true;
685 }
686 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000688 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689}
690
691//
692// Do size checking for an array type's size.
693//
694// Returns true if there was an error.
695//
Jamie Madill075edd82013-07-08 13:30:19 -0400696bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000697{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000698 TIntermConstantUnion* constant = expr->getAsConstantUnion();
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000699
700 if (constant == 0 || !constant->isScalarInt())
701 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000702 error(line, "array size must be a constant integer expression", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000703 return true;
704 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000705
Nicolas Capens906744a2014-06-06 15:18:07 -0400706 unsigned int unsignedSize = 0;
707
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000708 if (constant->getBasicType() == EbtUInt)
709 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400710 unsignedSize = constant->getUConst(0);
711 size = static_cast<int>(unsignedSize);
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000712 }
713 else
714 {
715 size = constant->getIConst(0);
716
Nicolas Capens906744a2014-06-06 15:18:07 -0400717 if (size < 0)
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000718 {
Nicolas Capens906744a2014-06-06 15:18:07 -0400719 error(line, "array size must be non-negative", "");
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +0000720 size = 1;
721 return true;
722 }
Nicolas Capens906744a2014-06-06 15:18:07 -0400723
724 unsignedSize = static_cast<unsigned int>(size);
725 }
726
727 if (size == 0)
728 {
729 error(line, "array size must be greater than zero", "");
730 size = 1;
731 return true;
732 }
733
734 // The size of arrays is restricted here to prevent issues further down the
735 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
736 // 4096 registers so this should be reasonable even for aggressively optimizable code.
737 const unsigned int sizeLimit = 65536;
738
739 if (unsignedSize > sizeLimit)
740 {
741 error(line, "array size too large", "");
742 size = 1;
743 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000744 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000745
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000746 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000747}
748
749//
750// See if this qualifier can be an array.
751//
752// Returns true if there is an error.
753//
Olli Etuaho3739d232015-04-08 12:23:44 +0300754bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000755{
Olli Etuaho3739d232015-04-08 12:23:44 +0300756 if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) ||
757 (type.qualifier == EvqConst && shaderVersion < 300))
758 {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000759 error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000760 return true;
761 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000762
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000763 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764}
765
766//
767// See if this type can be an array.
768//
769// Returns true if there is an error.
770//
Jamie Madill075edd82013-07-08 13:30:19 -0400771bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000772{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000773 //
774 // Can the type be an array?
775 //
776 if (type.array) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000777 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000778 return true;
779 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000780
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000781 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782}
783
784//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785// Enforce non-initializer type/qualifier rules.
786//
787// Returns true if there was an error.
788//
Olli Etuaho3739d232015-04-08 12:23:44 +0300789bool TParseContext::nonInitConstErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790{
Olli Etuaho3739d232015-04-08 12:23:44 +0300791 ASSERT(type != nullptr);
792 if (type->qualifier == EvqConst)
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000793 {
794 // Make the qualifier make sense.
Olli Etuaho3739d232015-04-08 12:23:44 +0300795 type->qualifier = EvqTemporary;
796
797 // Generate informative error messages for ESSL1.
798 // In ESSL3 arrays and structures containing arrays can be constant.
799 if (shaderVersion < 300 && type->isStructureContainingArrays())
daniel@transgaming.com8abd0b72012-09-27 17:46:07 +0000800 {
801 error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
802 }
803 else
804 {
805 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
806 }
807
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000808 return true;
809 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000810 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811}
812
Olli Etuaho2935c582015-04-08 14:32:06 +0300813// Do some simple checks that are shared between all variable declarations,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814// and update the symbol table.
815//
Olli Etuaho2935c582015-04-08 14:32:06 +0300816// Returns true if declaring the variable succeeded.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000817//
Olli Etuaho2935c582015-04-08 14:32:06 +0300818bool TParseContext::declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type,
819 TVariable **variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820{
Olli Etuaho2935c582015-04-08 14:32:06 +0300821 ASSERT((*variable) == nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000822
Olli Etuaho2935c582015-04-08 14:32:06 +0300823 bool needsReservedErrorCheck = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000824
Olli Etuaho2935c582015-04-08 14:32:06 +0300825 // gl_LastFragData may be redeclared with a new precision qualifier
826 if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
827 {
828 const TVariable *maxDrawBuffers =
829 static_cast<const TVariable *>(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion));
830 if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst())
831 {
832 if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, shaderVersion))
833 {
834 needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
835 }
836 }
837 else
838 {
839 error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers", identifier.c_str());
840 return false;
841 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000842 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000843
Olli Etuaho2935c582015-04-08 14:32:06 +0300844 if (needsReservedErrorCheck && reservedErrorCheck(line, identifier))
845 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000846
Olli Etuaho2935c582015-04-08 14:32:06 +0300847 (*variable) = new TVariable(&identifier, type);
848 if (!symbolTable.declare(*variable))
849 {
850 error(line, "redefinition", identifier.c_str());
851 delete (*variable);
852 (*variable) = nullptr;
853 return false;
854 }
855
856 if (voidErrorCheck(line, identifier, type.getBasicType()))
857 return false;
858
859 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000860}
861
Jamie Madill075edd82013-07-08 13:30:19 -0400862bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000863{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000864 if (qualifier != EvqConst && qualifier != EvqTemporary) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +0000865 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000866 return true;
867 }
868 if (qualifier == EvqConst && paramQualifier != EvqIn) {
869 error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
870 return true;
871 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000872
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000873 if (qualifier == EvqConst)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000874 type->setQualifier(EvqConstReadOnly);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000875 else
alokp@chromium.org58e54292010-08-24 21:40:03 +0000876 type->setQualifier(paramQualifier);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000877
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000878 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000879}
880
Jamie Madill075edd82013-07-08 13:30:19 -0400881bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000882{
alokp@chromium.org73bc2982012-06-19 18:48:05 +0000883 const TExtensionBehavior& extBehavior = extensionBehavior();
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000884 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
885 if (iter == extBehavior.end()) {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000886 error(line, "extension", extension.c_str(), "is not supported");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000887 return true;
888 }
zmo@google.comf5450912011-09-09 01:37:19 +0000889 // In GLSL ES, an extension's default behavior is "disable".
890 if (iter->second == EBhDisable || iter->second == EBhUndefined) {
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000891 error(line, "extension", extension.c_str(), "is disabled");
892 return true;
893 }
894 if (iter->second == EBhWarn) {
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000895 warning(line, "extension", extension.c_str(), "is being used");
alokp@chromium.org8815d7f2010-09-09 17:30:03 +0000896 return false;
897 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000898
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000899 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000900}
901
Jamie Madill075edd82013-07-08 13:30:19 -0400902bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
Jamie Madilla5efff92013-06-06 11:56:47 -0400903{
904 if (structQualifierErrorCheck(identifierLocation, publicType))
905 return true;
906
907 // check for layout qualifier issues
908 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
909
910 if (layoutQualifier.matrixPacking != EmpUnspecified)
911 {
912 error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -0400913 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400914 }
915
916 if (layoutQualifier.blockStorage != EbsUnspecified)
917 {
918 error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks");
Jamie Madill51a53c72013-06-19 09:24:43 -0400919 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400920 }
921
Jamie Madill19571812013-08-12 15:26:34 -0700922 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -0400923 {
Jamie Madill51a53c72013-06-19 09:24:43 -0400924 return true;
Jamie Madilla5efff92013-06-06 11:56:47 -0400925 }
926
927 return false;
928}
929
Jamie Madill075edd82013-07-08 13:30:19 -0400930bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier)
Jamie Madilla5efff92013-06-06 11:56:47 -0400931{
932 if (layoutQualifier.location != -1)
933 {
934 error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
935 return true;
936 }
937
938 return false;
939}
940
Olli Etuahob6e07a62015-02-16 12:22:10 +0200941bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate)
942{
943 for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
944 {
945 TQualifier qual = fnCandidate->getParam(i).type->getQualifier();
946 if (qual == EvqOut || qual == EvqInOut)
947 {
948 TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped();
949 if (lValueErrorCheck(node->getLine(), "assign", node))
950 {
951 error(node->getLine(),
952 "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
953 recover();
954 return true;
955 }
956 }
957 }
958 return false;
959}
960
zmo@google.com09c323a2011-08-12 18:22:25 +0000961bool TParseContext::supportsExtension(const char* extension)
962{
alokp@chromium.org73bc2982012-06-19 18:48:05 +0000963 const TExtensionBehavior& extbehavior = extensionBehavior();
964 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
965 return (iter != extbehavior.end());
alokp@chromium.org8b851c62012-06-15 16:25:11 +0000966}
967
Jamie Madill5d287f52013-07-12 15:38:19 -0400968bool TParseContext::isExtensionEnabled(const char* extension) const
969{
970 const TExtensionBehavior& extbehavior = extensionBehavior();
Shannon Woodsa49a9bf2013-08-02 17:23:14 -0400971 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
Jamie Madill5d287f52013-07-12 15:38:19 -0400972
973 if (iter == extbehavior.end())
974 {
975 return false;
976 }
977
978 return (iter->second == EBhEnable || iter->second == EBhRequire);
979}
980
Jamie Madill075edd82013-07-08 13:30:19 -0400981void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior)
982{
983 pp::SourceLocation srcLoc;
984 srcLoc.file = loc.first_file;
985 srcLoc.line = loc.first_line;
986 directiveHandler.handleExtension(srcLoc, extName, behavior);
987}
988
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700989void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl)
Jamie Madill075edd82013-07-08 13:30:19 -0400990{
991 pp::SourceLocation srcLoc;
992 srcLoc.file = loc.first_file;
993 srcLoc.line = loc.first_line;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700994 directiveHandler.handlePragma(srcLoc, name, value, stdgl);
Jamie Madill075edd82013-07-08 13:30:19 -0400995}
996
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997/////////////////////////////////////////////////////////////////////////////////
998//
999// Non-Errors.
1000//
1001/////////////////////////////////////////////////////////////////////////////////
1002
Jamie Madill5c097022014-08-20 16:38:32 -04001003const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
1004 const TString *name,
1005 const TSymbol *symbol)
1006{
1007 const TVariable *variable = NULL;
1008
1009 if (!symbol)
1010 {
1011 error(location, "undeclared identifier", name->c_str());
1012 recover();
1013 }
1014 else if (!symbol->isVariable())
1015 {
1016 error(location, "variable expected", name->c_str());
1017 recover();
1018 }
1019 else
1020 {
1021 variable = static_cast<const TVariable*>(symbol);
1022
1023 if (symbolTable.findBuiltIn(variable->getName(), shaderVersion) &&
1024 !variable->getExtension().empty() &&
1025 extensionErrorCheck(location, variable->getExtension()))
1026 {
1027 recover();
1028 }
1029 }
1030
1031 if (!variable)
1032 {
1033 TType type(EbtFloat, EbpUndefined);
1034 TVariable *fakeVariable = new TVariable(name, type);
1035 symbolTable.declare(fakeVariable);
1036 variable = fakeVariable;
1037 }
1038
1039 return variable;
1040}
1041
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001042//
1043// Look up a function name in the symbol table, and make sure it is a function.
1044//
1045// Return the function symbol if found, otherwise 0.
1046//
Austin Kinross3ae64652015-01-26 15:51:39 -08001047const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int inputShaderVersion, bool *builtIn)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001048{
alokp@chromium.org0a576182010-08-09 17:16:27 +00001049 // First find by unmangled name to check whether the function name has been
1050 // hidden by a variable name or struct typename.
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001051 // If a function is found, check for one with a matching argument list.
Austin Kinross3ae64652015-01-26 15:51:39 -08001052 const TSymbol* symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
Nicolas Capensd4a9b8d2013-07-18 11:01:22 -04001053 if (symbol == 0 || symbol->isFunction()) {
Austin Kinross3ae64652015-01-26 15:51:39 -08001054 symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
alokp@chromium.org0a576182010-08-09 17:16:27 +00001055 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001056
alokp@chromium.org0a576182010-08-09 17:16:27 +00001057 if (symbol == 0) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001058 error(line, "no matching overloaded function found", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001059 return 0;
1060 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061
alokp@chromium.org0a576182010-08-09 17:16:27 +00001062 if (!symbol->isFunction()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001063 error(line, "function name expected", call->getName().c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001064 return 0;
1065 }
alokp@chromium.org0a576182010-08-09 17:16:27 +00001066
1067 return static_cast<const TFunction*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068}
1069
1070//
1071// Initializers show up in several places in the grammar. Have one set of
1072// code to handle them here.
1073//
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001074// Returns true on error, false if no error
1075//
Olli Etuaho2935c582015-04-08 14:32:06 +03001076bool TParseContext::executeInitializer(const TSourceLoc &line, const TString &identifier, TPublicType &pType,
1077 TIntermTyped *initializer, TIntermNode *&intermNode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001078{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001079 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080
Olli Etuaho2935c582015-04-08 14:32:06 +03001081 TVariable *variable = nullptr;
1082 if (!declareVariable(line, identifier, type, &variable))
1083 {
1084 return true;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001085 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001086
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001087 //
1088 // identifier must be of type constant, a global, or a temporary
1089 //
1090 TQualifier qualifier = variable->getType().getQualifier();
1091 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001092 error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001093 return true;
1094 }
1095 //
1096 // test for and propagate constant
1097 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001099 if (qualifier == EvqConst) {
1100 if (qualifier != initializer->getType().getQualifier()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001101 std::stringstream extraInfoStream;
1102 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1103 std::string extraInfo = extraInfoStream.str();
1104 error(line, " assigning non-constant to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001105 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001106 return true;
1107 }
1108 if (type != initializer->getType()) {
1109 error(line, " non-matching types for const initializer ",
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001110 variable->getType().getQualifierString());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001111 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001112 return true;
1113 }
1114 if (initializer->getAsConstantUnion()) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001115 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001116 } else if (initializer->getAsSymbolNode()) {
shannonwoods@chromium.org96e7ba12013-05-30 00:02:41 +00001117 const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001118 const TVariable* tVar = static_cast<const TVariable*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001119
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001120 ConstantUnion* constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001121 variable->shareConstPointer(constArray);
1122 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001123 std::stringstream extraInfoStream;
1124 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1125 std::string extraInfo = extraInfoStream.str();
1126 error(line, " cannot assign to", "=", extraInfo.c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001127 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001128 return true;
1129 }
1130 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001132 if (qualifier != EvqConst) {
1133 TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
Olli Etuahod6b14282015-03-17 14:31:35 +02001134 intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001135 if (intermNode == 0) {
1136 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1137 return true;
1138 }
1139 } else
1140 intermNode = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001141
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001142 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143}
1144
1145bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
1146{
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001147 ASSERT(aggrNode != NULL);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001148 if (!aggrNode->isConstructor())
1149 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001151 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001152
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001153 // check if all the child nodes are constants so that they can be inserted into
1154 // the parent node
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001155 TIntermSequence *sequence = aggrNode->getSequence() ;
1156 for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p) {
alokp@chromium.orgd300f5b2010-10-14 16:10:20 +00001157 if (!(*p)->getAsTyped()->getAsConstantUnion())
1158 return false;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001159 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001160
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001161 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001162}
1163
Jamie Madilla5efff92013-06-06 11:56:47 -04001164TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001165{
1166 TPublicType returnType = typeSpecifier;
1167 returnType.qualifier = qualifier;
Jamie Madilla5efff92013-06-06 11:56:47 -04001168 returnType.layoutQualifier = layoutQualifier;
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001169
1170 if (typeSpecifier.array)
1171 {
1172 error(typeSpecifier.line, "not supported", "first-class array");
1173 recover();
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001174 returnType.clearArrayness();
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001175 }
1176
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001177 if (shaderVersion < 300)
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001178 {
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001179 if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1180 {
1181 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1182 recover();
1183 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001184
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001185 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1186 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1187 {
1188 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1189 recover();
1190 }
1191 }
1192 else
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001193 {
Jamie Madillb120eac2013-06-12 14:08:13 -04001194 switch (qualifier)
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001195 {
Jamie Madill19571812013-08-12 15:26:34 -07001196 case EvqSmoothIn:
1197 case EvqSmoothOut:
1198 case EvqVertexOut:
1199 case EvqFragmentIn:
1200 case EvqCentroidOut:
1201 case EvqCentroidIn:
1202 if (typeSpecifier.type == EbtBool)
1203 {
1204 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1205 recover();
1206 }
1207 if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
1208 {
1209 error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
1210 recover();
1211 }
1212 break;
1213
1214 case EvqVertexIn:
1215 case EvqFragmentOut:
1216 case EvqFlatIn:
1217 case EvqFlatOut:
Jamie Madillb120eac2013-06-12 14:08:13 -04001218 if (typeSpecifier.type == EbtBool)
1219 {
1220 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1221 recover();
1222 }
1223 break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001224
Jamie Madillb120eac2013-06-12 14:08:13 -04001225 default: break;
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001226 }
shannonwoods@chromium.org0f376ca2013-05-30 00:19:23 +00001227 }
1228
1229 return returnType;
1230}
1231
Jamie Madill075edd82013-07-08 13:30:19 -04001232TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
Jamie Madill60ed9812013-06-06 11:56:46 -04001233{
1234 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
1235 TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
1236
1237 if (identifier != "")
1238 {
Jamie Madill51a53c72013-06-19 09:24:43 -04001239 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
Jamie Madill60ed9812013-06-06 11:56:46 -04001240 recover();
1241
Olli Etuaho3739d232015-04-08 12:23:44 +03001242 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001243 recover();
1244
Olli Etuaho2935c582015-04-08 14:32:06 +03001245 TVariable *variable = nullptr;
1246 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001247 recover();
1248
1249 if (variable && symbol)
1250 {
1251 symbol->setId(variable->getUniqueId());
1252 }
1253 }
1254
1255 return aggregate;
1256}
1257
Jamie Madill075edd82013-07-08 13:30:19 -04001258TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression)
Jamie Madill60ed9812013-06-06 11:56:46 -04001259{
Jamie Madill51a53c72013-06-19 09:24:43 -04001260 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
Jamie Madill60ed9812013-06-06 11:56:46 -04001261 recover();
1262
Olli Etuaho3739d232015-04-08 12:23:44 +03001263 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill60ed9812013-06-06 11:56:46 -04001264 recover();
1265
1266 if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
1267 {
1268 recover();
1269 }
1270
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001271 TType arrayType(publicType);
Jamie Madill60ed9812013-06-06 11:56:46 -04001272
1273 int size;
1274 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1275 {
1276 recover();
1277 }
1278 else
1279 {
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001280 arrayType.setArraySize(size);
Jamie Madill60ed9812013-06-06 11:56:46 -04001281 }
1282
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001283 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001284 TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
Jamie Madill60ed9812013-06-06 11:56:46 -04001285
Olli Etuaho2935c582015-04-08 14:32:06 +03001286 TVariable *variable = nullptr;
1287 if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
Jamie Madill60ed9812013-06-06 11:56:46 -04001288 recover();
1289
1290 if (variable && symbol)
1291 {
1292 symbol->setId(variable->getUniqueId());
1293 }
1294
1295 return aggregate;
1296}
1297
Jamie Madill075edd82013-07-08 13:30:19 -04001298TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
Jamie Madill60ed9812013-06-06 11:56:46 -04001299{
Jamie Madilla5efff92013-06-06 11:56:47 -04001300 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
Jamie Madill60ed9812013-06-06 11:56:46 -04001301 recover();
1302
1303 TIntermNode* intermNode;
1304 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1305 {
1306 //
1307 // Build intermediate representation
1308 //
1309 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL;
1310 }
1311 else
1312 {
1313 recover();
1314 return NULL;
1315 }
1316}
1317
Jamie Madill47e3ec02014-08-20 16:38:33 -04001318TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
1319 const TSourceLoc &identifierLoc,
1320 const TString *identifier,
1321 const TSymbol *symbol)
1322{
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001323 // invariant declaration
Jamie Madill47e3ec02014-08-20 16:38:33 -04001324 if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying"))
1325 {
1326 recover();
1327 }
1328
1329 if (!symbol)
1330 {
1331 error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
1332 recover();
Jamie Madill47e3ec02014-08-20 16:38:33 -04001333 return NULL;
1334 }
1335 else
1336 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -07001337 const TString kGlFrontFacing("gl_FrontFacing");
1338 if (*identifier == kGlFrontFacing)
1339 {
1340 error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str());
1341 recover();
1342 return NULL;
1343 }
Jamie Madill2c433252014-12-03 12:36:54 -05001344 symbolTable.addInvariantVarying(std::string(identifier->c_str()));
Jamie Madill3b5c2da2014-08-19 15:23:32 -04001345 const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
1346 ASSERT(variable);
1347 const TType &type = variable->getType();
1348 TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(),
1349 *identifier, type, identifierLoc);
1350
1351 TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
1352 aggregate->setOp(EOpInvariantDeclaration);
1353 return aggregate;
Jamie Madill47e3ec02014-08-20 16:38:33 -04001354 }
1355}
1356
Jamie Madill075edd82013-07-08 13:30:19 -04001357TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
Jamie Madill502d66f2013-06-20 11:55:52 -04001358{
Jamie Madill502d66f2013-06-20 11:55:52 -04001359 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
1360 TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
1361
1362 if (structQualifierErrorCheck(identifierLocation, publicType))
1363 recover();
1364
Jamie Madill0bd18df2013-06-20 11:55:52 -04001365 if (locationDeclaratorListCheck(identifierLocation, publicType))
1366 recover();
1367
Olli Etuaho3739d232015-04-08 12:23:44 +03001368 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001369 recover();
1370
Olli Etuaho2935c582015-04-08 14:32:06 +03001371 TVariable *variable = nullptr;
1372 if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001373 recover();
1374 if (symbol && variable)
1375 symbol->setId(variable->getUniqueId());
1376
1377 return intermAggregate;
1378}
1379
Jamie Madill075edd82013-07-08 13:30:19 -04001380TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression)
Jamie Madill502d66f2013-06-20 11:55:52 -04001381{
1382 if (structQualifierErrorCheck(identifierLocation, publicType))
1383 recover();
1384
Jamie Madill0bd18df2013-06-20 11:55:52 -04001385 if (locationDeclaratorListCheck(identifierLocation, publicType))
1386 recover();
1387
Olli Etuaho3739d232015-04-08 12:23:44 +03001388 if (nonInitConstErrorCheck(identifierLocation, identifier, &publicType))
Jamie Madill502d66f2013-06-20 11:55:52 -04001389 recover();
1390
1391 if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
1392 {
1393 recover();
1394 }
Olli Etuaho93a90fd2015-04-07 18:14:07 +03001395 else
Jamie Madill502d66f2013-06-20 11:55:52 -04001396 {
1397 int size;
1398 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
1399 recover();
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001400 TType arrayType = TType(publicType);
Olli Etuaho693c9aa2015-04-07 17:50:36 +03001401 arrayType.setArraySize(size);
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001402 TVariable *variable = nullptr;
Olli Etuaho2935c582015-04-08 14:32:06 +03001403 if (!declareVariable(arrayLocation, identifier, arrayType, &variable))
Jamie Madill502d66f2013-06-20 11:55:52 -04001404 recover();
Jamie Madill502d66f2013-06-20 11:55:52 -04001405
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001406 TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
1407 if (variable && symbol)
1408 {
1409 symbol->setId(variable->getUniqueId());
1410 }
1411 return intermediate.growAggregate(declaratorList, symbol, identifierLocation);
Jamie Madill502d66f2013-06-20 11:55:52 -04001412 }
Jamie Madill502d66f2013-06-20 11:55:52 -04001413
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03001414 return nullptr;
Jamie Madill502d66f2013-06-20 11:55:52 -04001415}
1416
Jamie Madill075edd82013-07-08 13:30:19 -04001417TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
Jamie Madill502d66f2013-06-20 11:55:52 -04001418{
1419 if (structQualifierErrorCheck(identifierLocation, publicType))
1420 recover();
1421
Jamie Madill0bd18df2013-06-20 11:55:52 -04001422 if (locationDeclaratorListCheck(identifierLocation, publicType))
1423 recover();
1424
Jamie Madill502d66f2013-06-20 11:55:52 -04001425 TIntermNode* intermNode;
1426 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1427 {
1428 //
1429 // build the intermediate representation
1430 //
1431 if (intermNode)
1432 {
1433 return intermediate.growAggregate(declaratorList, intermNode, initLocation);
1434 }
1435 else
1436 {
1437 return declaratorList;
1438 }
1439 }
1440 else
1441 {
1442 recover();
1443 return NULL;
1444 }
1445}
1446
Jamie Madilla295edf2013-06-06 11:56:48 -04001447void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1448{
1449 if (typeQualifier.qualifier != EvqUniform)
1450 {
1451 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
1452 recover();
1453 return;
1454 }
1455
1456 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1457 ASSERT(!layoutQualifier.isEmpty());
1458
1459 if (shaderVersion < 300)
1460 {
1461 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1462 recover();
1463 return;
1464 }
1465
1466 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1467 {
1468 recover();
1469 return;
1470 }
1471
Jamie Madill099c0f32013-06-20 11:55:52 -04001472 if (layoutQualifier.matrixPacking != EmpUnspecified)
1473 {
1474 defaultMatrixPacking = layoutQualifier.matrixPacking;
1475 }
1476
Geoff Langc6856732014-02-11 09:38:55 -05001477 if (layoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001478 {
1479 defaultBlockStorage = layoutQualifier.blockStorage;
1480 }
Jamie Madilla295edf2013-06-06 11:56:48 -04001481}
1482
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001483TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
1484{
1485 TOperator op = EOpNull;
1486 if (publicType.userDef)
1487 {
1488 op = EOpConstructStruct;
1489 }
1490 else
1491 {
1492 switch (publicType.type)
1493 {
1494 case EbtFloat:
1495 if (publicType.isMatrix())
1496 {
1497 // TODO: non-square matrices
1498 switch(publicType.getCols())
1499 {
Jamie Madill28b97422013-07-08 14:01:38 -04001500 case 2: op = EOpConstructMat2; break;
1501 case 3: op = EOpConstructMat3; break;
1502 case 4: op = EOpConstructMat4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001503 }
1504 }
1505 else
1506 {
1507 switch(publicType.getNominalSize())
1508 {
Jamie Madill28b97422013-07-08 14:01:38 -04001509 case 1: op = EOpConstructFloat; break;
1510 case 2: op = EOpConstructVec2; break;
1511 case 3: op = EOpConstructVec3; break;
1512 case 4: op = EOpConstructVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001513 }
1514 }
1515 break;
1516
1517 case EbtInt:
1518 switch(publicType.getNominalSize())
1519 {
Jamie Madill28b97422013-07-08 14:01:38 -04001520 case 1: op = EOpConstructInt; break;
1521 case 2: op = EOpConstructIVec2; break;
1522 case 3: op = EOpConstructIVec3; break;
1523 case 4: op = EOpConstructIVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001524 }
1525 break;
1526
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001527 case EbtUInt:
1528 switch(publicType.getNominalSize())
1529 {
Jamie Madill28b97422013-07-08 14:01:38 -04001530 case 1: op = EOpConstructUInt; break;
1531 case 2: op = EOpConstructUVec2; break;
1532 case 3: op = EOpConstructUVec3; break;
1533 case 4: op = EOpConstructUVec4; break;
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001534 }
1535 break;
1536
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001537 case EbtBool:
1538 switch(publicType.getNominalSize())
1539 {
Jamie Madill28b97422013-07-08 14:01:38 -04001540 case 1: op = EOpConstructBool; break;
1541 case 2: op = EOpConstructBVec2; break;
1542 case 3: op = EOpConstructBVec3; break;
1543 case 4: op = EOpConstructBVec4; break;
shannonwoods@chromium.org18851132013-05-30 00:19:54 +00001544 }
1545 break;
1546
1547 default: break;
1548 }
1549
1550 if (op == EOpNull)
1551 {
1552 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
1553 recover();
1554 publicType.type = EbtFloat;
1555 op = EOpConstructFloat;
1556 }
1557 }
1558
1559 TString tempString;
1560 TType type(publicType);
1561 return new TFunction(&tempString, type, op);
1562}
1563
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001564// This function is used to test for the correctness of the parameters passed to various constructor functions
1565// and also convert them to the right datatype if it is allowed and required.
1566//
1567// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
1568//
Olli Etuaho21203702014-11-13 16:16:21 +02001569TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001570{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001571 TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001572
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001573 if (!aggregateArguments)
1574 {
1575 aggregateArguments = new TIntermAggregate;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001576 aggregateArguments->getSequence()->push_back(arguments);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001577 }
1578
Olli Etuahof40319e2015-03-10 14:33:00 +02001579 if (type->isArray())
1580 {
1581 // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of the array.
1582 TIntermSequence *args = aggregateArguments->getSequence();
1583 for (size_t i = 0; i < args->size(); i++)
1584 {
1585 const TType &argType = (*args)[i]->getAsTyped()->getType();
1586 // It has already been checked that the argument is not an array.
1587 ASSERT(!argType.isArray());
1588 if (!argType.sameElementType(*type))
1589 {
1590 error(line, "Array constructor argument has an incorrect type", "Error");
1591 recover();
1592 return nullptr;
1593 }
1594 }
1595 }
1596 else if (op == EOpConstructStruct)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001597 {
1598 const TFieldList &fields = type->getStruct()->fields();
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001599 TIntermSequence *args = aggregateArguments->getSequence();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001600
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001601 for (size_t i = 0; i < fields.size(); i++)
1602 {
Nicolas Capensffd73872014-08-21 13:49:16 -04001603 if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001604 {
1605 error(line, "Structure constructor arguments do not match structure fields", "Error");
1606 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001608 return 0;
1609 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001610 }
1611 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001612
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001613 // Turn the argument list itself into a constructor
Olli Etuaho21203702014-11-13 16:16:21 +02001614 TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
1615 TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001616 if (constConstructor)
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001617 {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001618 return constConstructor;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04001619 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001620
Olli Etuaho21203702014-11-13 16:16:21 +02001621 // Structs should not be precision qualified, the individual members may be.
1622 // Built-in types on the other hand should be precision qualified.
1623 if (op != EOpConstructStruct)
1624 {
1625 constructor->setPrecisionFromChildren();
1626 type->setPrecision(constructor->getPrecision());
1627 }
1628
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001629 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630}
1631
1632TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
1633{
Olli Etuahof40319e2015-03-10 14:33:00 +02001634 // TODO: Add support for folding array constructors
1635 bool canBeFolded = areAllChildConst(aggrNode) && !type.isArray();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001636 aggrNode->setType(type);
1637 if (canBeFolded) {
1638 bool returnVal = false;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001639 ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001640 if (aggrNode->getSequence()->size() == 1) {
shannonwoods@chromium.org298f9072013-05-30 00:21:17 +00001641 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001642 }
1643 else {
shannonwoods@chromium.org298f9072013-05-30 00:21:17 +00001644 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001645 }
1646 if (returnVal)
1647 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001648
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001649 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
1650 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001652 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001653}
1654
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655//
1656// This function returns the tree representation for the vector field(s) being accessed from contant vector.
1657// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
1658// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
1659// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
1660// a constant matrix.
1661//
Jamie Madill075edd82013-07-08 13:30:19 -04001662TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001664 TIntermTyped* typedNode;
1665 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001666
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001667 ConstantUnion *unionArray;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001668 if (tempConstantNode) {
1669 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001670
alokp@chromium.org8b851c62012-06-15 16:25:11 +00001671 if (!unionArray) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001672 return node;
1673 }
1674 } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001675 error(line, "Cannot offset into the vector", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001676 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001677
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001678 return 0;
1679 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001680
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001681 ConstantUnion* constArray = new ConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001682
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001683 for (int i = 0; i < fields.num; i++) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001684 if (fields.offsets[i] >= node->getType().getNominalSize()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001685 std::stringstream extraInfoStream;
1686 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
1687 std::string extraInfo = extraInfoStream.str();
1688 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001689 recover();
1690 fields.offsets[i] = 0;
1691 }
1692
1693 constArray[i] = unionArray[fields.offsets[i]];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001694
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001695 }
1696 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
1697 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001698}
1699
1700//
1701// This function returns the column being accessed from a constant matrix. The values are retrieved from
1702// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
1703// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
1704// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
1705//
Jamie Madill075edd82013-07-08 13:30:19 -04001706TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001708 TIntermTyped* typedNode;
1709 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001710
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001711 if (index >= node->getType().getCols()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001712 std::stringstream extraInfoStream;
1713 extraInfoStream << "matrix field selection out of range '" << index << "'";
1714 std::string extraInfo = extraInfoStream.str();
1715 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001716 recover();
1717 index = 0;
1718 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001719
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001720 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001721 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00001722 int size = tempConstantNode->getType().getCols();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001723 typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
1724 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001725 error(line, "Cannot offset into the matrix", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001726 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001727
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001728 return 0;
1729 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001730
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001731 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001732}
1733
1734
1735//
1736// This function returns an element of an array accessed from a constant array. The values are retrieved from
1737// the symbol table and parse-tree is built for the type of the element. The input
1738// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
1739// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
1740//
Jamie Madill075edd82013-07-08 13:30:19 -04001741TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001742{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001743 TIntermTyped* typedNode;
1744 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1745 TType arrayElementType = node->getType();
1746 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001747
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001748 if (index >= node->getType().getArraySize()) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001749 std::stringstream extraInfoStream;
1750 extraInfoStream << "array field selection out of range '" << index << "'";
1751 std::string extraInfo = extraInfoStream.str();
1752 error(line, "", "[", extraInfo.c_str());
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001753 recover();
1754 index = 0;
1755 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001757 if (tempConstantNode) {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001758 size_t arrayElementSize = arrayElementType.getObjectSize();
1759 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
1760 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001761 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001762 error(line, "Cannot offset into the array", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001763 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001764
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001765 return 0;
1766 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001768 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001769}
1770
1771
1772//
1773// This function returns the value of a particular field inside a constant structure from the symbol table.
1774// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
1775// function and returns the parse-tree with the values of the embedded/nested struct.
1776//
Jamie Madill075edd82013-07-08 13:30:19 -04001777TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001778{
Jamie Madill98493dd2013-07-08 14:39:03 -04001779 const TFieldList& fields = node->getType().getStruct()->fields();
Jamie Madill94bf7f22013-07-08 13:31:15 -04001780 size_t instanceSize = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001781
Jamie Madill98493dd2013-07-08 14:39:03 -04001782 for (size_t index = 0; index < fields.size(); ++index) {
1783 if (fields[index]->name() == identifier) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001784 break;
1785 } else {
Jamie Madill98493dd2013-07-08 14:39:03 -04001786 instanceSize += fields[index]->type()->getObjectSize();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001787 }
1788 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789
Jamie Madill94bf7f22013-07-08 13:31:15 -04001790 TIntermTyped *typedNode;
1791 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001792 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001793 ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001794
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001795 typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
1796 } else {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001797 error(line, "Cannot offset into the structure", "Error");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001798 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001799
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001800 return 0;
1801 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001802
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001803 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001804}
1805
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001806//
1807// Interface/uniform blocks
1808//
Jamie Madill98493dd2013-07-08 14:39:03 -04001809TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
1810 const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001811{
1812 if (reservedErrorCheck(nameLine, blockName))
1813 recover();
1814
1815 if (typeQualifier.qualifier != EvqUniform)
1816 {
1817 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
1818 recover();
1819 }
1820
Jamie Madill099c0f32013-06-20 11:55:52 -04001821 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
1822 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001823 {
1824 recover();
1825 }
1826
Jamie Madill099c0f32013-06-20 11:55:52 -04001827 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
1828 {
1829 blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
1830 }
1831
Jamie Madill1566ef72013-06-20 11:55:54 -04001832 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
1833 {
1834 blockLayoutQualifier.blockStorage = defaultBlockStorage;
1835 }
1836
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001837 TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
Nicolas Capensadfffe42014-06-17 02:13:36 -04001838 if (!symbolTable.declare(blockNameSymbol)) {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001839 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
1840 recover();
1841 }
1842
Jamie Madill98493dd2013-07-08 14:39:03 -04001843 // check for sampler types and apply layout qualifiers
1844 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
1845 TField* field = (*fieldList)[memberIndex];
1846 TType* fieldType = field->type();
1847 if (IsSampler(fieldType->getBasicType())) {
1848 error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001849 recover();
1850 }
1851
Jamie Madill98493dd2013-07-08 14:39:03 -04001852 const TQualifier qualifier = fieldType->getQualifier();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001853 switch (qualifier)
1854 {
1855 case EvqGlobal:
1856 case EvqUniform:
1857 break;
1858 default:
Jamie Madill98493dd2013-07-08 14:39:03 -04001859 error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001860 recover();
1861 break;
1862 }
Jamie Madilla5efff92013-06-06 11:56:47 -04001863
1864 // check layout qualifiers
Jamie Madill98493dd2013-07-08 14:39:03 -04001865 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
1866 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
Jamie Madilla5efff92013-06-06 11:56:47 -04001867 {
1868 recover();
1869 }
Jamie Madill099c0f32013-06-20 11:55:52 -04001870
Jamie Madill98493dd2013-07-08 14:39:03 -04001871 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
Jamie Madill1566ef72013-06-20 11:55:54 -04001872 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001873 error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
Jamie Madill1566ef72013-06-20 11:55:54 -04001874 recover();
1875 }
1876
Jamie Madill98493dd2013-07-08 14:39:03 -04001877 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
Jamie Madill099c0f32013-06-20 11:55:52 -04001878 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001879 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
Jamie Madill099c0f32013-06-20 11:55:52 -04001880 }
Jamie Madill98493dd2013-07-08 14:39:03 -04001881 else if (!fieldType->isMatrix())
Jamie Madill099c0f32013-06-20 11:55:52 -04001882 {
Jamie Madill98493dd2013-07-08 14:39:03 -04001883 error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
Jamie Madill099c0f32013-06-20 11:55:52 -04001884 recover();
1885 }
1886
Jamie Madill98493dd2013-07-08 14:39:03 -04001887 fieldType->setLayoutQualifier(fieldLayoutQualifier);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001888 }
1889
Jamie Madill98493dd2013-07-08 14:39:03 -04001890 // add array index
1891 int arraySize = 0;
1892 if (arrayIndex != NULL)
1893 {
1894 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
1895 recover();
1896 }
1897
1898 TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
1899 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001900
1901 TString symbolName = "";
1902 int symbolId = 0;
1903
Jamie Madill98493dd2013-07-08 14:39:03 -04001904 if (!instanceName)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001905 {
1906 // define symbols for the members of the interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04001907 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
1908 {
1909 TField* field = (*fieldList)[memberIndex];
1910 TType* fieldType = field->type();
1911
1912 // set parent pointer of the field variable
1913 fieldType->setInterfaceBlock(interfaceBlock);
1914
1915 TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
1916 fieldVariable->setQualifier(typeQualifier.qualifier);
1917
Nicolas Capensadfffe42014-06-17 02:13:36 -04001918 if (!symbolTable.declare(fieldVariable)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04001919 error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001920 recover();
1921 }
1922 }
1923 }
1924 else
1925 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001926 // add a symbol for this interface block
Jamie Madill98493dd2013-07-08 14:39:03 -04001927 TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001928 instanceTypeDef->setQualifier(typeQualifier.qualifier);
Jamie Madill98493dd2013-07-08 14:39:03 -04001929
Nicolas Capensadfffe42014-06-17 02:13:36 -04001930 if (!symbolTable.declare(instanceTypeDef)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04001931 error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001932 recover();
1933 }
1934
1935 symbolId = instanceTypeDef->getUniqueId();
1936 symbolName = instanceTypeDef->getName();
1937 }
1938
Jamie Madill98493dd2013-07-08 14:39:03 -04001939 TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001940 aggregate->setOp(EOpDeclaration);
Jamie Madill98493dd2013-07-08 14:39:03 -04001941
1942 exitStructDeclaration();
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00001943 return aggregate;
1944}
1945
Jamie Madill075edd82013-07-08 13:30:19 -04001946bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
kbr@chromium.org476541f2011-10-27 21:14:51 +00001947{
1948 ++structNestingLevel;
1949
1950 // Embedded structure definitions are not supported per GLSL ES spec.
1951 // They aren't allowed in GLSL either, but we need to detect this here
1952 // so we don't rely on the GLSL compiler to catch it.
1953 if (structNestingLevel > 1) {
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00001954 error(line, "", "Embedded struct definitions are not allowed");
kbr@chromium.org476541f2011-10-27 21:14:51 +00001955 return true;
1956 }
1957
1958 return false;
1959}
1960
1961void TParseContext::exitStructDeclaration()
1962{
1963 --structNestingLevel;
1964}
1965
1966namespace {
1967
1968const int kWebGLMaxStructNesting = 4;
1969
1970} // namespace
1971
Jamie Madill98493dd2013-07-08 14:39:03 -04001972bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
kbr@chromium.org476541f2011-10-27 21:14:51 +00001973{
Jamie Madill5508f392014-02-20 13:31:36 -05001974 if (!IsWebGLBasedSpec(shaderSpec)) {
kbr@chromium.org476541f2011-10-27 21:14:51 +00001975 return false;
1976 }
1977
Jamie Madill98493dd2013-07-08 14:39:03 -04001978 if (field.type()->getBasicType() != EbtStruct) {
kbr@chromium.org476541f2011-10-27 21:14:51 +00001979 return false;
1980 }
1981
1982 // We're already inside a structure definition at this point, so add
1983 // one to the field's struct nesting.
Jamie Madill98493dd2013-07-08 14:39:03 -04001984 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
Jamie Madill41a49272014-03-18 16:10:13 -04001985 std::stringstream reasonStream;
1986 reasonStream << "Reference of struct type "
1987 << field.type()->getStruct()->name().c_str()
1988 << " exceeds maximum allowed nesting level of "
1989 << kWebGLMaxStructNesting;
1990 std::string reason = reasonStream.str();
1991 error(line, reason.c_str(), field.name().c_str(), "");
kbr@chromium.org476541f2011-10-27 21:14:51 +00001992 return true;
1993 }
1994
1995 return false;
1996}
1997
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00001998//
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00001999// Parse an array index expression
2000//
Jamie Madill075edd82013-07-08 13:30:19 -04002001TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002002{
2003 TIntermTyped *indexedExpression = NULL;
2004
2005 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2006 {
2007 if (baseExpression->getAsSymbolNode())
2008 {
2009 error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
2010 }
2011 else
2012 {
2013 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2014 }
2015 recover();
2016 }
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002017
Jamie Madill21c1e452014-12-29 11:33:41 -05002018 TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
2019
2020 if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
Jamie Madill7164cf42013-07-08 13:30:59 -04002021 {
Jamie Madill21c1e452014-12-29 11:33:41 -05002022 int index = indexConstantUnion->getIConst(0);
Jamie Madill7164cf42013-07-08 13:30:59 -04002023 if (index < 0)
2024 {
2025 std::stringstream infoStream;
2026 infoStream << index;
2027 std::string info = infoStream.str();
2028 error(location, "negative index", info.c_str());
2029 recover();
2030 index = 0;
2031 }
2032 if (baseExpression->getType().getQualifier() == EvqConst)
2033 {
2034 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002035 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002036 // constant folding for arrays
2037 indexedExpression = addConstArrayNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002038 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002039 else if (baseExpression->isVector())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002040 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002041 // constant folding for vectors
2042 TVectorFields fields;
2043 fields.num = 1;
2044 fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
2045 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2046 }
2047 else if (baseExpression->isMatrix())
2048 {
2049 // constant folding for matrices
2050 indexedExpression = addConstMatrixNode(index, baseExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002051 }
2052 }
2053 else
2054 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002055 if (baseExpression->isArray())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002056 {
Jamie Madill18464b52013-07-08 14:01:55 -04002057 if (index >= baseExpression->getType().getArraySize())
Jamie Madill7164cf42013-07-08 13:30:59 -04002058 {
2059 std::stringstream extraInfoStream;
2060 extraInfoStream << "array index out of range '" << index << "'";
2061 std::string extraInfo = extraInfoStream.str();
2062 error(location, "", "[", extraInfo.c_str());
2063 recover();
2064 index = baseExpression->getType().getArraySize() - 1;
2065 }
Jamie Madill5d287f52013-07-12 15:38:19 -04002066 else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
2067 {
2068 error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
2069 recover();
2070 index = 0;
2071 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002072 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002073 else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002074 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002075 std::stringstream extraInfoStream;
2076 extraInfoStream << "field selection out of range '" << index << "'";
2077 std::string extraInfo = extraInfoStream.str();
2078 error(location, "", "[", extraInfo.c_str());
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002079 recover();
Jamie Madill7164cf42013-07-08 13:30:59 -04002080 index = baseExpression->getType().getNominalSize() - 1;
Jamie Madill46131a32013-06-20 11:55:50 -04002081 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002082
Jamie Madill21c1e452014-12-29 11:33:41 -05002083 indexConstantUnion->getUnionArrayPointer()->setIConst(index);
Jamie Madill7164cf42013-07-08 13:30:59 -04002084 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002085 }
2086 }
Jamie Madill7164cf42013-07-08 13:30:59 -04002087 else
2088 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002089 if (baseExpression->isInterfaceBlock())
Jamie Madill7164cf42013-07-08 13:30:59 -04002090 {
Jamie Madill19571812013-08-12 15:26:34 -07002091 error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002092 recover();
2093 }
Jamie Madill19571812013-08-12 15:26:34 -07002094 else if (baseExpression->getQualifier() == EvqFragmentOut)
Jamie Madill7164cf42013-07-08 13:30:59 -04002095 {
Jamie Madill19571812013-08-12 15:26:34 -07002096 error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions");
Jamie Madill7164cf42013-07-08 13:30:59 -04002097 recover();
2098 }
2099
2100 indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
2101 }
2102
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002103 if (indexedExpression == 0)
2104 {
2105 ConstantUnion *unionArray = new ConstantUnion[1];
2106 unionArray->setFConst(0.0f);
2107 indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
2108 }
2109 else if (baseExpression->isArray())
2110 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002111 const TType &baseType = baseExpression->getType();
2112 if (baseType.getStruct())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002113 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002114 TType copyOfType(baseType.getStruct());
2115 indexedExpression->setType(copyOfType);
2116 }
2117 else if (baseType.isInterfaceBlock())
2118 {
2119 TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0);
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002120 indexedExpression->setType(copyOfType);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002121 }
2122 else
2123 {
Minmin Gong794e0002015-04-07 18:31:54 -07002124 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary,
2125 static_cast<unsigned char>(baseExpression->getNominalSize()), static_cast<unsigned char>(baseExpression->getSecondarySize())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002126 }
2127
2128 if (baseExpression->getType().getQualifier() == EvqConst)
2129 {
2130 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2131 }
2132 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002133 else if (baseExpression->isMatrix())
2134 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002135 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
Minmin Gong794e0002015-04-07 18:31:54 -07002136 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002137 }
2138 else if (baseExpression->isVector())
2139 {
Jamie Madill7164cf42013-07-08 13:30:59 -04002140 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2141 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002142 }
2143 else
2144 {
2145 indexedExpression->setType(baseExpression->getType());
2146 }
2147
2148 return indexedExpression;
2149}
2150
Jamie Madill075edd82013-07-08 13:30:19 -04002151TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002152{
2153 TIntermTyped *indexedExpression = NULL;
2154
2155 if (baseExpression->isArray())
2156 {
2157 error(fieldLocation, "cannot apply dot operator to an array", ".");
2158 recover();
2159 }
2160
2161 if (baseExpression->isVector())
2162 {
2163 TVectorFields fields;
2164 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation))
2165 {
2166 fields.num = 1;
2167 fields.offsets[0] = 0;
2168 recover();
2169 }
2170
2171 if (baseExpression->getType().getQualifier() == EvqConst)
2172 {
2173 // constant folding for vector fields
2174 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2175 if (indexedExpression == 0)
2176 {
2177 recover();
2178 indexedExpression = baseExpression;
2179 }
2180 else
2181 {
Minmin Gong794e0002015-04-07 18:31:54 -07002182 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (unsigned char) (fieldString).size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002183 }
2184 }
2185 else
2186 {
2187 TString vectorString = fieldString;
2188 TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation);
2189 indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
Minmin Gong794e0002015-04-07 18:31:54 -07002190 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (unsigned char) vectorString.size()));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002191 }
2192 }
2193 else if (baseExpression->isMatrix())
2194 {
2195 TMatrixFields fields;
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002196 if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002197 {
2198 fields.wholeRow = false;
2199 fields.wholeCol = false;
2200 fields.row = 0;
2201 fields.col = 0;
2202 recover();
2203 }
2204
2205 if (fields.wholeRow || fields.wholeCol)
2206 {
2207 error(dotLocation, " non-scalar fields not implemented yet", ".");
2208 recover();
2209 ConstantUnion *unionArray = new ConstantUnion[1];
2210 unionArray->setIConst(0);
2211 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2212 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
Minmin Gong794e0002015-04-07 18:31:54 -07002213 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary,
2214 static_cast<unsigned char>(baseExpression->getCols()), static_cast<unsigned char>(baseExpression->getRows())));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002215 }
2216 else
2217 {
2218 ConstantUnion *unionArray = new ConstantUnion[1];
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002219 unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002220 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2221 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
2222 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
2223 }
2224 }
2225 else if (baseExpression->getBasicType() == EbtStruct)
2226 {
2227 bool fieldFound = false;
Jamie Madill98493dd2013-07-08 14:39:03 -04002228 const TFieldList& fields = baseExpression->getType().getStruct()->fields();
2229 if (fields.empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002230 {
2231 error(dotLocation, "structure has no fields", "Internal Error");
2232 recover();
2233 indexedExpression = baseExpression;
2234 }
2235 else
2236 {
2237 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002238 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002239 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002240 if (fields[i]->name() == fieldString)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002241 {
2242 fieldFound = true;
2243 break;
2244 }
2245 }
2246 if (fieldFound)
2247 {
2248 if (baseExpression->getType().getQualifier() == EvqConst)
2249 {
2250 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
2251 if (indexedExpression == 0)
2252 {
2253 recover();
2254 indexedExpression = baseExpression;
2255 }
2256 else
2257 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002258 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002259 // change the qualifier of the return type, not of the structure field
2260 // as the structure definition is shared between various structures.
2261 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2262 }
2263 }
2264 else
2265 {
2266 ConstantUnion *unionArray = new ConstantUnion[1];
2267 unionArray->setIConst(i);
Jamie Madill98493dd2013-07-08 14:39:03 -04002268 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002269 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04002270 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002271 }
2272 }
2273 else
2274 {
2275 error(dotLocation, " no such field in structure", fieldString.c_str());
2276 recover();
2277 indexedExpression = baseExpression;
2278 }
2279 }
2280 }
Jamie Madill98493dd2013-07-08 14:39:03 -04002281 else if (baseExpression->isInterfaceBlock())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002282 {
2283 bool fieldFound = false;
Jamie Madill98493dd2013-07-08 14:39:03 -04002284 const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields();
2285 if (fields.empty())
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002286 {
2287 error(dotLocation, "interface block has no fields", "Internal Error");
2288 recover();
2289 indexedExpression = baseExpression;
2290 }
2291 else
2292 {
2293 unsigned int i;
Jamie Madill98493dd2013-07-08 14:39:03 -04002294 for (i = 0; i < fields.size(); ++i)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002295 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002296 if (fields[i]->name() == fieldString)
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002297 {
2298 fieldFound = true;
2299 break;
2300 }
2301 }
2302 if (fieldFound)
2303 {
2304 ConstantUnion *unionArray = new ConstantUnion[1];
2305 unionArray->setIConst(i);
Jamie Madill98493dd2013-07-08 14:39:03 -04002306 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002307 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
Jamie Madill98493dd2013-07-08 14:39:03 -04002308 indexedExpression->setType(*fields[i]->type());
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002309 }
2310 else
2311 {
2312 error(dotLocation, " no such field in interface block", fieldString.c_str());
2313 recover();
2314 indexedExpression = baseExpression;
2315 }
2316 }
2317 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002318 else
2319 {
shannonwoods@chromium.org5668c5d2013-05-30 00:11:48 +00002320 if (shaderVersion < 300)
2321 {
2322 error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
2323 }
2324 else
2325 {
2326 error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
2327 }
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002328 recover();
2329 indexedExpression = baseExpression;
2330 }
2331
2332 return indexedExpression;
2333}
2334
Jamie Madill075edd82013-07-08 13:30:19 -04002335TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002336{
Jamie Madilla5efff92013-06-06 11:56:47 -04002337 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002338
Jamie Madilla5efff92013-06-06 11:56:47 -04002339 qualifier.location = -1;
2340 qualifier.matrixPacking = EmpUnspecified;
2341 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002342
2343 if (qualifierType == "shared")
2344 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002345 qualifier.blockStorage = EbsShared;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002346 }
2347 else if (qualifierType == "packed")
2348 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002349 qualifier.blockStorage = EbsPacked;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002350 }
2351 else if (qualifierType == "std140")
2352 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002353 qualifier.blockStorage = EbsStd140;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002354 }
2355 else if (qualifierType == "row_major")
2356 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002357 qualifier.matrixPacking = EmpRowMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002358 }
2359 else if (qualifierType == "column_major")
2360 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002361 qualifier.matrixPacking = EmpColumnMajor;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002362 }
2363 else if (qualifierType == "location")
2364 {
2365 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument");
2366 recover();
2367 }
2368 else
2369 {
2370 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
2371 recover();
2372 }
2373
Jamie Madilla5efff92013-06-06 11:56:47 -04002374 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002375}
2376
Jamie Madill075edd82013-07-08 13:30:19 -04002377TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002378{
Jamie Madilla5efff92013-06-06 11:56:47 -04002379 TLayoutQualifier qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002380
Jamie Madilla5efff92013-06-06 11:56:47 -04002381 qualifier.location = -1;
2382 qualifier.matrixPacking = EmpUnspecified;
2383 qualifier.blockStorage = EbsUnspecified;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002384
2385 if (qualifierType != "location")
2386 {
2387 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments");
2388 recover();
2389 }
2390 else
2391 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04002392 // must check that location is non-negative
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002393 if (intValue < 0)
2394 {
Jamie Madill05a80ce2013-06-20 11:55:49 -04002395 error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002396 recover();
2397 }
2398 else
2399 {
Jamie Madilla5efff92013-06-06 11:56:47 -04002400 qualifier.location = intValue;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002401 }
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002402 }
2403
Jamie Madilla5efff92013-06-06 11:56:47 -04002404 return qualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002405}
2406
Jamie Madilla5efff92013-06-06 11:56:47 -04002407TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002408{
Jamie Madilla5efff92013-06-06 11:56:47 -04002409 TLayoutQualifier joinedQualifier = leftQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002410
Jamie Madilla5efff92013-06-06 11:56:47 -04002411 if (rightQualifier.location != -1)
2412 {
2413 joinedQualifier.location = rightQualifier.location;
2414 }
2415 if (rightQualifier.matrixPacking != EmpUnspecified)
2416 {
2417 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
2418 }
2419 if (rightQualifier.blockStorage != EbsUnspecified)
2420 {
2421 joinedQualifier.blockStorage = rightQualifier.blockStorage;
2422 }
2423
2424 return joinedQualifier;
shannonwoods@chromium.org302adfe2013-05-30 00:21:06 +00002425}
2426
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002427TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
2428 const TSourceLoc &storageLoc, TQualifier storageQualifier)
2429{
2430 TQualifier mergedQualifier = EvqSmoothIn;
2431
Jamie Madill19571812013-08-12 15:26:34 -07002432 if (storageQualifier == EvqFragmentIn) {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002433 if (interpolationQualifier == EvqSmooth)
2434 mergedQualifier = EvqSmoothIn;
2435 else if (interpolationQualifier == EvqFlat)
2436 mergedQualifier = EvqFlatIn;
2437 else UNREACHABLE();
2438 }
2439 else if (storageQualifier == EvqCentroidIn) {
2440 if (interpolationQualifier == EvqSmooth)
2441 mergedQualifier = EvqCentroidIn;
2442 else if (interpolationQualifier == EvqFlat)
2443 mergedQualifier = EvqFlatIn;
2444 else UNREACHABLE();
2445 }
Jamie Madill19571812013-08-12 15:26:34 -07002446 else if (storageQualifier == EvqVertexOut) {
Jamie Madillf2e0f9b2013-08-26 16:39:42 -04002447 if (interpolationQualifier == EvqSmooth)
2448 mergedQualifier = EvqSmoothOut;
2449 else if (interpolationQualifier == EvqFlat)
2450 mergedQualifier = EvqFlatOut;
2451 else UNREACHABLE();
2452 }
2453 else if (storageQualifier == EvqCentroidOut) {
2454 if (interpolationQualifier == EvqSmooth)
2455 mergedQualifier = EvqCentroidOut;
2456 else if (interpolationQualifier == EvqFlat)
2457 mergedQualifier = EvqFlatOut;
2458 else UNREACHABLE();
2459 }
2460 else {
2461 error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier));
2462 recover();
2463
2464 mergedQualifier = storageQualifier;
2465 }
2466
2467 TPublicType type;
2468 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
2469 return type;
2470}
2471
Jamie Madill98493dd2013-07-08 14:39:03 -04002472TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002473{
Olli Etuaho6ed7bbe2015-04-07 18:08:46 +03002474 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
2475 {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002476 recover();
2477 }
2478
Jamie Madill98493dd2013-07-08 14:39:03 -04002479 for (unsigned int i = 0; i < fieldList->size(); ++i) {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002480 //
2481 // Careful not to replace already known aspects of type, like array-ness
2482 //
Jamie Madill98493dd2013-07-08 14:39:03 -04002483 TType* type = (*fieldList)[i]->type();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002484 type->setBasicType(typeSpecifier.type);
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00002485 type->setPrimarySize(typeSpecifier.primarySize);
2486 type->setSecondarySize(typeSpecifier.secondarySize);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002487 type->setPrecision(typeSpecifier.precision);
2488 type->setQualifier(typeSpecifier.qualifier);
Jamie Madilla5efff92013-06-06 11:56:47 -04002489 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002490
2491 // don't allow arrays of arrays
2492 if (type->isArray()) {
2493 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
2494 recover();
2495 }
2496 if (typeSpecifier.array)
2497 type->setArraySize(typeSpecifier.arraySize);
2498 if (typeSpecifier.userDef) {
2499 type->setStruct(typeSpecifier.userDef->getStruct());
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002500 }
2501
Jamie Madill98493dd2013-07-08 14:39:03 -04002502 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) {
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002503 recover();
2504 }
2505 }
2506
Jamie Madill98493dd2013-07-08 14:39:03 -04002507 return fieldList;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002508}
2509
Jamie Madill98493dd2013-07-08 14:39:03 -04002510TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002511{
Jamie Madill98493dd2013-07-08 14:39:03 -04002512 TStructure* structure = new TStructure(structName, fieldList);
2513 TType* structureType = new TType(structure);
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002514
Jamie Madill9b820842015-02-12 10:40:10 -05002515 // Store a bool in the struct if we're at global scope, to allow us to
2516 // skip the local struct scoping workaround in HLSL.
Jamie Madillb960cc42015-02-12 15:33:20 +00002517 structure->setUniqueId(TSymbolTable::nextUniqueId());
Jamie Madill9b820842015-02-12 10:40:10 -05002518 structure->setAtGlobalScope(symbolTable.atGlobalLevel());
Jamie Madillbfa91f42014-06-05 15:45:18 -04002519
Jamie Madill98493dd2013-07-08 14:39:03 -04002520 if (!structName->empty())
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002521 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002522 if (reservedErrorCheck(nameLine, *structName))
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002523 {
2524 recover();
2525 }
Jamie Madill98493dd2013-07-08 14:39:03 -04002526 TVariable* userTypeDef = new TVariable(structName, *structureType, true);
Nicolas Capensadfffe42014-06-17 02:13:36 -04002527 if (!symbolTable.declare(userTypeDef)) {
Jamie Madill98493dd2013-07-08 14:39:03 -04002528 error(nameLine, "redefinition", structName->c_str(), "struct");
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002529 recover();
2530 }
2531 }
2532
2533 // ensure we do not specify any storage qualifiers on the struct members
Jamie Madill98493dd2013-07-08 14:39:03 -04002534 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002535 {
Jamie Madill98493dd2013-07-08 14:39:03 -04002536 const TField &field = *(*fieldList)[typeListIndex];
2537 const TQualifier qualifier = field.type()->getQualifier();
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002538 switch (qualifier)
2539 {
2540 case EvqGlobal:
2541 case EvqTemporary:
2542 break;
2543 default:
Jamie Madill98493dd2013-07-08 14:39:03 -04002544 error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002545 recover();
2546 break;
2547 }
2548 }
2549
2550 TPublicType publicType;
2551 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
Jamie Madill98493dd2013-07-08 14:39:03 -04002552 publicType.userDef = structureType;
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00002553 exitStructDeclaration();
2554
2555 return publicType;
2556}
2557
Olli Etuahoa3a36662015-02-17 13:46:51 +02002558TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
2559{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002560 TBasicType switchType = init->getBasicType();
2561 if ((switchType != EbtInt && switchType != EbtUInt) ||
2562 init->isMatrix() ||
2563 init->isArray() ||
2564 init->isVector())
2565 {
2566 error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
2567 recover();
2568 return nullptr;
2569 }
2570
Olli Etuahoac5274d2015-02-20 10:19:08 +02002571 if (statementList)
2572 {
2573 if (!ValidateSwitch::validate(switchType, this, statementList, loc))
2574 {
2575 recover();
2576 return nullptr;
2577 }
2578 }
2579
Olli Etuahoa3a36662015-02-17 13:46:51 +02002580 TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
2581 if (node == nullptr)
2582 {
2583 error(loc, "erroneous switch statement", "switch");
2584 recover();
2585 return nullptr;
2586 }
2587 return node;
2588}
2589
2590TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
2591{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002592 if (mSwitchNestingLevel == 0)
2593 {
2594 error(loc, "case labels need to be inside switch statements", "case");
2595 recover();
2596 return nullptr;
2597 }
2598 if (condition == nullptr)
2599 {
2600 error(loc, "case label must have a condition", "case");
2601 recover();
2602 return nullptr;
2603 }
2604 if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
2605 condition->isMatrix() ||
2606 condition->isArray() ||
2607 condition->isVector())
2608 {
2609 error(condition->getLine(), "case label must be a scalar integer", "case");
2610 recover();
2611 }
2612 TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
2613 if (conditionConst == nullptr)
2614 {
2615 error(condition->getLine(), "case label must be constant", "case");
2616 recover();
2617 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02002618 TIntermCase *node = intermediate.addCase(condition, loc);
2619 if (node == nullptr)
2620 {
2621 error(loc, "erroneous case statement", "case");
2622 recover();
2623 return nullptr;
2624 }
2625 return node;
2626}
2627
2628TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
2629{
Olli Etuaho53f076f2015-02-20 10:55:14 +02002630 if (mSwitchNestingLevel == 0)
2631 {
2632 error(loc, "default labels need to be inside switch statements", "default");
2633 recover();
2634 return nullptr;
2635 }
Olli Etuahoa3a36662015-02-17 13:46:51 +02002636 TIntermCase *node = intermediate.addCase(nullptr, loc);
2637 if (node == nullptr)
2638 {
2639 error(loc, "erroneous default statement", "default");
2640 recover();
2641 return nullptr;
2642 }
2643 return node;
2644}
2645
Olli Etuahof6c694b2015-03-26 14:50:53 +02002646TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc,
2647 const TType *funcReturnType)
Olli Etuaho69c11b52015-03-26 12:59:00 +02002648{
2649 if (child == nullptr)
2650 {
2651 return nullptr;
2652 }
2653
2654 switch (op)
2655 {
2656 case EOpLogicalNot:
2657 if (child->getBasicType() != EbtBool ||
2658 child->isMatrix() ||
2659 child->isArray() ||
2660 child->isVector())
2661 {
2662 return nullptr;
2663 }
2664 break;
2665 case EOpBitwiseNot:
2666 if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
2667 child->isMatrix() ||
2668 child->isArray())
2669 {
2670 return nullptr;
2671 }
2672 break;
2673 case EOpPostIncrement:
2674 case EOpPreIncrement:
2675 case EOpPostDecrement:
2676 case EOpPreDecrement:
2677 case EOpNegative:
2678 case EOpPositive:
2679 if (child->getBasicType() == EbtStruct ||
Olli Etuahodca3e792015-03-26 13:24:04 +02002680 child->getBasicType() == EbtBool ||
Olli Etuaho69c11b52015-03-26 12:59:00 +02002681 child->isArray())
2682 {
2683 return nullptr;
2684 }
Olli Etuahodca3e792015-03-26 13:24:04 +02002685 // Operators for built-ins are already type checked against their prototype.
Olli Etuaho69c11b52015-03-26 12:59:00 +02002686 default:
2687 break;
2688 }
2689
Olli Etuahof6c694b2015-03-26 14:50:53 +02002690 return intermediate.addUnaryMath(op, child, loc, funcReturnType);
Olli Etuaho69c11b52015-03-26 12:59:00 +02002691}
2692
Olli Etuaho09b22472015-02-11 11:47:26 +02002693TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
2694{
Olli Etuahof6c694b2015-03-26 14:50:53 +02002695 TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
Olli Etuaho69c11b52015-03-26 12:59:00 +02002696 if (node == nullptr)
Olli Etuaho09b22472015-02-11 11:47:26 +02002697 {
2698 unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
2699 recover();
2700 return child;
2701 }
2702 return node;
2703}
2704
2705TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
2706{
2707 if (lValueErrorCheck(loc, GetOperatorString(op), child))
2708 recover();
2709 return addUnaryMath(op, child, loc);
2710}
2711
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002712bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
Olli Etuahod6b14282015-03-17 14:31:35 +02002713 const TSourceLoc &loc)
2714{
2715 if (left->isArray() || right->isArray())
2716 {
Olli Etuahoe79904c2015-03-18 16:56:42 +02002717 if (shaderVersion < 300)
2718 {
2719 error(loc, "Invalid operation for arrays", GetOperatorString(op));
2720 return false;
2721 }
2722
2723 if (left->isArray() != right->isArray())
2724 {
2725 error(loc, "array / non-array mismatch", GetOperatorString(op));
2726 return false;
2727 }
2728
2729 switch (op)
2730 {
2731 case EOpEqual:
2732 case EOpNotEqual:
2733 case EOpAssign:
2734 case EOpInitialize:
2735 break;
2736 default:
2737 error(loc, "Invalid operation for arrays", GetOperatorString(op));
2738 return false;
2739 }
2740 if (left->getArraySize() != right->getArraySize())
2741 {
2742 error(loc, "array size mismatch", GetOperatorString(op));
2743 return false;
2744 }
Olli Etuahod6b14282015-03-17 14:31:35 +02002745 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002746
2747 // Check ops which require integer / ivec parameters
2748 bool isBitShift = false;
2749 switch (op)
2750 {
2751 case EOpBitShiftLeft:
2752 case EOpBitShiftRight:
2753 case EOpBitShiftLeftAssign:
2754 case EOpBitShiftRightAssign:
2755 // Unsigned can be bit-shifted by signed and vice versa, but we need to
2756 // check that the basic type is an integer type.
2757 isBitShift = true;
2758 if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
2759 {
2760 return false;
2761 }
2762 break;
2763 case EOpBitwiseAnd:
2764 case EOpBitwiseXor:
2765 case EOpBitwiseOr:
2766 case EOpBitwiseAndAssign:
2767 case EOpBitwiseXorAssign:
2768 case EOpBitwiseOrAssign:
2769 // It is enough to check the type of only one operand, since later it
2770 // is checked that the operand types match.
2771 if (!IsInteger(left->getBasicType()))
2772 {
2773 return false;
2774 }
2775 break;
2776 default:
2777 break;
2778 }
2779
2780 // GLSL ES 1.00 and 3.00 do not support implicit type casting.
2781 // So the basic type should usually match.
2782 if (!isBitShift && left->getBasicType() != right->getBasicType())
2783 {
2784 return false;
2785 }
2786
Olli Etuaho9dd217b2015-03-20 14:24:31 +02002787 // Check that type sizes match exactly on ops that require that.
Olli Etuahoff699002015-03-23 14:38:42 +02002788 // Also check restrictions for structs that contain arrays or samplers.
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002789 switch(op)
2790 {
2791 case EOpAssign:
2792 case EOpInitialize:
2793 case EOpEqual:
2794 case EOpNotEqual:
Olli Etuaho9dd217b2015-03-20 14:24:31 +02002795 // ESSL 1.00 sections 5.7, 5.8, 5.9
2796 if (shaderVersion < 300 && left->getType().isStructureContainingArrays())
2797 {
2798 error(loc, "undefined operation for structs containing arrays", GetOperatorString(op));
2799 return false;
2800 }
Olli Etuahoff699002015-03-23 14:38:42 +02002801 // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
2802 // we interpret the spec so that this extends to structs containing samplers,
2803 // similarly to ESSL 1.00 spec.
2804 if ((shaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
2805 left->getType().isStructureContainingSamplers())
2806 {
2807 error(loc, "undefined operation for structs containing samplers", GetOperatorString(op));
2808 return false;
2809 }
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002810 case EOpLessThan:
2811 case EOpGreaterThan:
2812 case EOpLessThanEqual:
2813 case EOpGreaterThanEqual:
2814 if ((left->getNominalSize() != right->getNominalSize()) ||
2815 (left->getSecondarySize() != right->getSecondarySize()))
2816 {
2817 return false;
2818 }
2819 default:
2820 break;
2821 }
2822
Olli Etuahod6b14282015-03-17 14:31:35 +02002823 return true;
2824}
2825
Olli Etuahofc1806e2015-03-17 13:03:11 +02002826TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
2827 const TSourceLoc &loc)
2828{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002829 if (!binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02002830 return nullptr;
2831
Olli Etuahofc1806e2015-03-17 13:03:11 +02002832 switch (op)
2833 {
2834 case EOpEqual:
2835 case EOpNotEqual:
Olli Etuahofc1806e2015-03-17 13:03:11 +02002836 break;
2837 case EOpLessThan:
2838 case EOpGreaterThan:
2839 case EOpLessThanEqual:
2840 case EOpGreaterThanEqual:
Olli Etuahod6b14282015-03-17 14:31:35 +02002841 ASSERT(!left->isArray() && !right->isArray());
2842 if (left->isMatrix() || left->isVector() ||
Olli Etuahofc1806e2015-03-17 13:03:11 +02002843 left->getBasicType() == EbtStruct)
2844 {
2845 return nullptr;
2846 }
2847 break;
2848 case EOpLogicalOr:
2849 case EOpLogicalXor:
2850 case EOpLogicalAnd:
Olli Etuahod6b14282015-03-17 14:31:35 +02002851 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002852 if (left->getBasicType() != EbtBool ||
Olli Etuahod6b14282015-03-17 14:31:35 +02002853 left->isMatrix() || left->isVector())
Olli Etuahofc1806e2015-03-17 13:03:11 +02002854 {
2855 return nullptr;
2856 }
2857 break;
2858 case EOpAdd:
2859 case EOpSub:
2860 case EOpDiv:
2861 case EOpMul:
Olli Etuahod6b14282015-03-17 14:31:35 +02002862 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002863 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
2864 {
2865 return nullptr;
2866 }
2867 break;
2868 case EOpIMod:
Olli Etuahod6b14282015-03-17 14:31:35 +02002869 ASSERT(!left->isArray() && !right->isArray());
Olli Etuahofc1806e2015-03-17 13:03:11 +02002870 // Note that this is only for the % operator, not for mod()
2871 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
2872 {
2873 return nullptr;
2874 }
2875 break;
2876 // Note that for bitwise ops, type checking is done in promote() to
2877 // share code between ops and compound assignment
2878 default:
2879 break;
2880 }
2881
Olli Etuahofc1806e2015-03-17 13:03:11 +02002882 return intermediate.addBinaryMath(op, left, right, loc);
2883}
2884
Olli Etuaho09b22472015-02-11 11:47:26 +02002885TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right,
2886 const TSourceLoc &loc)
2887{
Olli Etuahofc1806e2015-03-17 13:03:11 +02002888 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02002889 if (node == 0)
2890 {
2891 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
2892 recover();
2893 return left;
2894 }
2895 return node;
2896}
2897
2898TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
2899 const TSourceLoc &loc)
2900{
Olli Etuahofc1806e2015-03-17 13:03:11 +02002901 TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
Olli Etuaho09b22472015-02-11 11:47:26 +02002902 if (node == 0)
2903 {
2904 binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
2905 recover();
2906 ConstantUnion *unionArray = new ConstantUnion[1];
2907 unionArray->setBConst(false);
2908 return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), loc);
2909 }
2910 return node;
2911}
2912
Olli Etuahod6b14282015-03-17 14:31:35 +02002913TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
2914 const TSourceLoc &loc)
2915{
Olli Etuaho47fd36a2015-03-19 14:22:24 +02002916 if (binaryOpCommonCheck(op, left, right, loc))
Olli Etuahod6b14282015-03-17 14:31:35 +02002917 {
2918 return intermediate.addAssign(op, left, right, loc);
2919 }
2920 return nullptr;
2921}
2922
2923TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
2924 const TSourceLoc &loc)
2925{
2926 TIntermTyped *node = createAssign(op, left, right, loc);
2927 if (node == nullptr)
2928 {
2929 assignError(loc, "assign", left->getCompleteString(), right->getCompleteString());
2930 recover();
2931 return left;
2932 }
2933 return node;
2934}
2935
Olli Etuaho49300862015-02-20 14:54:49 +02002936TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
2937{
2938 switch (op)
2939 {
2940 case EOpContinue:
2941 if (mLoopNestingLevel <= 0)
2942 {
2943 error(loc, "continue statement only allowed in loops", "");
2944 recover();
2945 }
2946 break;
2947 case EOpBreak:
Olli Etuaho53f076f2015-02-20 10:55:14 +02002948 if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
Olli Etuaho49300862015-02-20 14:54:49 +02002949 {
Olli Etuaho53f076f2015-02-20 10:55:14 +02002950 error(loc, "break statement only allowed in loops and switch statements", "");
Olli Etuaho49300862015-02-20 14:54:49 +02002951 recover();
2952 }
2953 break;
2954 case EOpReturn:
2955 if (currentFunctionType->getBasicType() != EbtVoid)
2956 {
2957 error(loc, "non-void function must return a value", "return");
2958 recover();
2959 }
2960 break;
2961 default:
2962 // No checks for discard
2963 break;
2964 }
2965 return intermediate.addBranch(op, loc);
2966}
2967
2968TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
2969{
2970 ASSERT(op == EOpReturn);
2971 mFunctionReturnsValue = true;
2972 if (currentFunctionType->getBasicType() == EbtVoid)
2973 {
2974 error(loc, "void function cannot return a value", "return");
2975 recover();
2976 }
2977 else if (*currentFunctionType != returnValue->getType())
2978 {
2979 error(loc, "function return is not matching type:", "return");
2980 recover();
2981 }
2982 return intermediate.addBranch(op, returnValue, loc);
2983}
2984
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02002985TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
2986 const TSourceLoc &loc, bool *fatalError)
2987{
2988 *fatalError = false;
2989 TOperator op = fnCall->getBuiltInOp();
2990 TIntermTyped *callNode = nullptr;
2991
2992 if (op != EOpNull)
2993 {
2994 //
2995 // Then this should be a constructor.
2996 // Don't go through the symbol table for constructors.
2997 // Their parameters will be verified algorithmically.
2998 //
2999 TType type(EbtVoid, EbpUndefined); // use this to get the type back
3000 if (!constructorErrorCheck(loc, node, *fnCall, op, &type))
3001 {
3002 //
3003 // It's a constructor, of type 'type'.
3004 //
3005 callNode = addConstructor(node, &type, op, fnCall, loc);
3006 }
Olli Etuaho72ba85b2015-03-04 14:23:26 +02003007
3008 if (callNode == nullptr)
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003009 {
3010 recover();
3011 callNode = intermediate.setAggregateOperator(nullptr, op, loc);
3012 }
3013 callNode->setType(type);
3014 }
3015 else
3016 {
3017 //
3018 // Not a constructor. Find it in the symbol table.
3019 //
3020 const TFunction* fnCandidate;
3021 bool builtIn;
3022 fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn);
3023 if (fnCandidate)
3024 {
3025 //
3026 // A declared function.
3027 //
3028 if (builtIn && !fnCandidate->getExtension().empty() &&
3029 extensionErrorCheck(loc, fnCandidate->getExtension()))
3030 {
3031 recover();
3032 }
3033 op = fnCandidate->getBuiltInOp();
3034 if (builtIn && op != EOpNull)
3035 {
3036 //
3037 // A function call mapped to a built-in operation.
3038 //
3039 if (fnCandidate->getParamCount() == 1)
3040 {
3041 //
3042 // Treat it like a built-in unary operator.
3043 //
Olli Etuahof6c694b2015-03-26 14:50:53 +02003044 callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003045 if (callNode == nullptr)
3046 {
3047 std::stringstream extraInfoStream;
3048 extraInfoStream << "built in unary operator function. Type: "
3049 << static_cast<TIntermTyped*>(node)->getCompleteString();
3050 std::string extraInfo = extraInfoStream.str();
3051 error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
3052 *fatalError = true;
3053 return nullptr;
3054 }
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003055 }
3056 else
3057 {
3058 TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc);
3059 aggregate->setType(fnCandidate->getReturnType());
3060 aggregate->setPrecisionFromChildren();
3061 callNode = aggregate;
3062
3063 // Some built-in functions have out parameters too.
3064 functionCallLValueErrorCheck(fnCandidate, aggregate);
3065 }
3066 }
3067 else
3068 {
3069 // This is a real function call
3070
3071 TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc);
3072 aggregate->setType(fnCandidate->getReturnType());
3073
3074 // this is how we know whether the given function is a builtIn function or a user defined function
3075 // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
3076 // if builtIn == true, it's definitely a builtIn function with EOpNull
3077 if (!builtIn)
3078 aggregate->setUserDefined();
3079 aggregate->setName(fnCandidate->getMangledName());
Corentin Wallez71d147f2015-02-11 11:15:24 -08003080 aggregate->setFunctionId(fnCandidate->getUniqueId());
Olli Etuahoc4ba3be2015-03-02 14:42:24 +02003081
3082 // This needs to happen after the name is set
3083 if (builtIn)
3084 aggregate->setBuiltInFunctionPrecision();
3085
3086 callNode = aggregate;
3087
3088 functionCallLValueErrorCheck(fnCandidate, aggregate);
3089 }
3090 }
3091 else
3092 {
3093 // error message was put out by findFunction()
3094 // Put on a dummy node for error recovery
3095 ConstantUnion *unionArray = new ConstantUnion[1];
3096 unionArray->setFConst(0.0f);
3097 callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc);
3098 recover();
3099 }
3100 }
3101 delete fnCall;
3102 return callNode;
3103}
3104
Olli Etuaho49300862015-02-20 14:54:49 +02003105
shannonwoods@chromium.orga9100882013-05-30 00:11:39 +00003106//
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003107// Parse an array of strings using yyparse.
3108//
3109// Returns 0 for success.
3110//
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +00003111int PaParseStrings(size_t count, const char* const string[], const int length[],
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003112 TParseContext* context) {
3113 if ((count == 0) || (string == NULL))
3114 return 1;
3115
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003116 if (glslang_initialize(context))
3117 return 1;
3118
alokp@chromium.org408c45e2012-04-05 15:54:43 +00003119 int error = glslang_scan(count, string, length, context);
3120 if (!error)
3121 error = glslang_parse(context);
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003122
alokp@chromium.org73bc2982012-06-19 18:48:05 +00003123 glslang_finalize(context);
alokp@chromium.org8b851c62012-06-15 16:25:11 +00003124
alokp@chromium.org6b495712012-06-29 00:06:58 +00003125 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
alokp@chromium.org044a5cf2010-11-12 15:42:16 +00003126}
3127
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003128
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00003129