blob: 407226bc2f034841dbd18beed0a3cc94de416bf0 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00007#include "compiler/ParseHelper.h"
8
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
12#include "compiler/osinclude.h"
13#include "compiler/InitializeParseContext.h"
14
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015///////////////////////////////////////////////////////////////////////
16//
17// Sub- vector and matrix fields
18//
19////////////////////////////////////////////////////////////////////////
20
21//
22// Look at a '.' field selector string and change it into offsets
23// for a vector.
24//
25bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line)
26{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000027 fields.num = (int) compString.size();
28 if (fields.num > 4) {
29 error(line, "illegal vector field selection", compString.c_str(), "");
30 return false;
31 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000033 enum {
34 exyzw,
35 ergba,
36 estpq,
37 } fieldSet[4];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000039 for (int i = 0; i < fields.num; ++i) {
40 switch (compString[i]) {
41 case 'x':
42 fields.offsets[i] = 0;
43 fieldSet[i] = exyzw;
44 break;
45 case 'r':
46 fields.offsets[i] = 0;
47 fieldSet[i] = ergba;
48 break;
49 case 's':
50 fields.offsets[i] = 0;
51 fieldSet[i] = estpq;
52 break;
53 case 'y':
54 fields.offsets[i] = 1;
55 fieldSet[i] = exyzw;
56 break;
57 case 'g':
58 fields.offsets[i] = 1;
59 fieldSet[i] = ergba;
60 break;
61 case 't':
62 fields.offsets[i] = 1;
63 fieldSet[i] = estpq;
64 break;
65 case 'z':
66 fields.offsets[i] = 2;
67 fieldSet[i] = exyzw;
68 break;
69 case 'b':
70 fields.offsets[i] = 2;
71 fieldSet[i] = ergba;
72 break;
73 case 'p':
74 fields.offsets[i] = 2;
75 fieldSet[i] = estpq;
76 break;
77
78 case 'w':
79 fields.offsets[i] = 3;
80 fieldSet[i] = exyzw;
81 break;
82 case 'a':
83 fields.offsets[i] = 3;
84 fieldSet[i] = ergba;
85 break;
86 case 'q':
87 fields.offsets[i] = 3;
88 fieldSet[i] = estpq;
89 break;
90 default:
91 error(line, "illegal vector field selection", compString.c_str(), "");
92 return false;
93 }
94 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +000096 for (int i = 0; i < fields.num; ++i) {
97 if (fields.offsets[i] >= vecSize) {
98 error(line, "vector field selection out of range", compString.c_str(), "");
99 return false;
100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000102 if (i > 0) {
103 if (fieldSet[i] != fieldSet[i-1]) {
104 error(line, "illegal - vector component fields not from the same set", compString.c_str(), "");
105 return false;
106 }
107 }
108 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000110 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000111}
112
113
114//
115// Look at a '.' field selector string and change it into offsets
116// for a matrix.
117//
118bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line)
119{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000120 fields.wholeRow = false;
121 fields.wholeCol = false;
122 fields.row = -1;
123 fields.col = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000125 if (compString.size() != 2) {
126 error(line, "illegal length of matrix field selection", compString.c_str(), "");
127 return false;
128 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000130 if (compString[0] == '_') {
131 if (compString[1] < '0' || compString[1] > '3') {
132 error(line, "illegal matrix field selection", compString.c_str(), "");
133 return false;
134 }
135 fields.wholeCol = true;
136 fields.col = compString[1] - '0';
137 } else if (compString[1] == '_') {
138 if (compString[0] < '0' || compString[0] > '3') {
139 error(line, "illegal matrix field selection", compString.c_str(), "");
140 return false;
141 }
142 fields.wholeRow = true;
143 fields.row = compString[0] - '0';
144 } else {
145 if (compString[0] < '0' || compString[0] > '3' ||
146 compString[1] < '0' || compString[1] > '3') {
147 error(line, "illegal matrix field selection", compString.c_str(), "");
148 return false;
149 }
150 fields.row = compString[0] - '0';
151 fields.col = compString[1] - '0';
152 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000154 if (fields.row >= matSize || fields.col >= matSize) {
155 error(line, "matrix field selection out of range", compString.c_str(), "");
156 return false;
157 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000159 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160}
161
162///////////////////////////////////////////////////////////////////////
163//
164// Errors
165//
166////////////////////////////////////////////////////////////////////////
167
168//
169// Track whether errors have occurred.
170//
171void TParseContext::recover()
172{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000173 recoveredFromError = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174}
175
176//
177// Used by flex/bison to output all syntax and parsing errors.
178//
alokp@chromium.orgc54bf502010-07-22 16:49:09 +0000179void TParseContext::error(TSourceLoc nLine, const char *szReason, const char *szToken,
180 const char *szExtraInfoFormat, ...)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000182 char szExtraInfo[400];
183 va_list marker;
alokp@chromium.orgff42c632010-05-10 15:14:30 +0000184
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000185 va_start(marker, szExtraInfoFormat);
alokp@chromium.orgff42c632010-05-10 15:14:30 +0000186
187 vsnprintf(szExtraInfo, sizeof(szExtraInfo), szExtraInfoFormat, marker);
188
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000189 /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
190 infoSink.info.prefix(EPrefixError);
191 infoSink.info.location(nLine);
192 infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n";
alokp@chromium.orgff42c632010-05-10 15:14:30 +0000193
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000194 va_end(marker);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000196 ++numErrors;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197}
198
199//
200// Same error message for all places assignments don't work.
201//
202void TParseContext::assignError(int line, const char* op, TString left, TString right)
203{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000204 error(line, "", op, "cannot convert from '%s' to '%s'",
205 right.c_str(), left.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206}
207
208//
209// Same error message for all places unary operations don't work.
210//
211void TParseContext::unaryOpError(int line, const char* op, TString operand)
212{
213 error(line, " wrong operand type", op,
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000214 "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)",
215 op, operand.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216}
217
218//
219// Same error message for all binary operations don't work.
220//
221void TParseContext::binaryOpError(int line, const char* op, TString left, TString right)
222{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000223 error(line, " wrong operand types ", op,
224 "no operation '%s' exists that takes a left-hand operand of type '%s' and "
225 "a right operand of type '%s' (or there is no acceptable conversion)",
226 op, left.c_str(), right.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227}
228
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000229bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){
230 switch( type ){
231 case EbtFloat:
232 if( precision == EbpUndefined ){
233 error( line, "No precision specified for (float)", "", "" );
234 return true;
235 }
236 break;
237 case EbtInt:
238 if( precision == EbpUndefined ){
239 error( line, "No precision specified (int)", "", "" );
240 return true;
241 }
242 break;
243 }
244 return false;
245}
246
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000247//
248// Both test and if necessary, spit out an error, to see if the node is really
249// an l-value that can be operated on this way.
250//
251// Returns true if the was an error.
252//
253bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node)
254{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000255 TIntermSymbol* symNode = node->getAsSymbolNode();
256 TIntermBinary* binaryNode = node->getAsBinaryNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000258 if (binaryNode) {
259 bool errorReturn;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000261 switch(binaryNode->getOp()) {
262 case EOpIndexDirect:
263 case EOpIndexIndirect:
264 case EOpIndexDirectStruct:
265 return lValueErrorCheck(line, op, binaryNode->getLeft());
266 case EOpVectorSwizzle:
267 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
268 if (!errorReturn) {
269 int offset[4] = {0,0,0,0};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000271 TIntermTyped* rightNode = binaryNode->getRight();
272 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
273
274 for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
275 p != aggrNode->getSequence().end(); p++) {
276 int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
277 offset[value]++;
278 if (offset[value] > 1) {
279 error(line, " l-value of swizzle cannot have duplicate components", op, "", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000281 return true;
282 }
283 }
284 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000286 return errorReturn;
287 default:
288 break;
289 }
290 error(line, " l-value required", op, "", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000292 return true;
293 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294
295
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000296 const char* symbol = 0;
297 if (symNode != 0)
298 symbol = symNode->getSymbol().c_str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000300 const char* message = 0;
301 switch (node->getQualifier()) {
302 case EvqConst: message = "can't modify a const"; break;
303 case EvqConstReadOnly: message = "can't modify a const"; break;
304 case EvqAttribute: message = "can't modify an attribute"; break;
305 case EvqUniform: message = "can't modify a uniform"; break;
306 case EvqVaryingIn: message = "can't modify a varying"; break;
307 case EvqInput: message = "can't modify an input"; break;
308 case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
309 case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
310 case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
311 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000313 //
314 // Type that can't be written to?
315 //
316 switch (node->getBasicType()) {
317 case EbtSampler2D:
318 case EbtSamplerCube:
319 message = "can't modify a sampler";
320 break;
321 case EbtVoid:
322 message = "can't modify void";
323 break;
324 default:
325 break;
326 }
327 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000329 if (message == 0 && binaryNode == 0 && symNode == 0) {
330 error(line, " l-value required", op, "", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000332 return true;
333 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334
335
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000336 //
337 // Everything else is okay, no error.
338 //
339 if (message == 0)
340 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000342 //
343 // If we get here, we have an error and a message.
344 //
345 if (symNode)
346 error(line, " l-value required", op, "\"%s\" (%s)", symbol, message);
347 else
348 error(line, " l-value required", op, "(%s)", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000350 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351}
352
353//
354// Both test, and if necessary spit out an error, to see if the node is really
355// a constant.
356//
357// Returns true if the was an error.
358//
359bool TParseContext::constErrorCheck(TIntermTyped* node)
360{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000361 if (node->getQualifier() == EvqConst)
362 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000363
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000364 error(node->getLine(), "constant expression required", "", "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000366 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367}
368
369//
370// Both test, and if necessary spit out an error, to see if the node is really
371// an integer.
372//
373// Returns true if the was an error.
374//
375bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
376{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000377 if (node->getBasicType() == EbtInt && node->getNominalSize() == 1)
378 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000380 error(node->getLine(), "integer expression required", token, "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000382 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383}
384
385//
386// Both test, and if necessary spit out an error, to see if we are currently
387// globally scoped.
388//
389// Returns true if the was an error.
390//
391bool TParseContext::globalErrorCheck(int line, bool global, const char* token)
392{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000393 if (global)
394 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000395
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000396 error(line, "only allowed at global scope", token, "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000397
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000398 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000399}
400
401//
402// For now, keep it simple: if it starts "gl_", it's reserved, independent
403// of scope. Except, if the symbol table is at the built-in push-level,
404// which is when we are parsing built-ins.
alokp@chromium.org613ef312010-07-21 18:54:22 +0000405// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
406// webgl shader.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407//
408// Returns true if there was an error.
409//
410bool TParseContext::reservedErrorCheck(int line, const TString& identifier)
411{
alokp@chromium.org613ef312010-07-21 18:54:22 +0000412 static const char* reservedErrMsg = "reserved built-in name";
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000413 if (!symbolTable.atBuiltInLevel()) {
414 if (identifier.substr(0, 3) == TString("gl_")) {
alokp@chromium.org613ef312010-07-21 18:54:22 +0000415 error(line, reservedErrMsg, "gl_", "");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000416 return true;
417 }
alokp@chromium.org613ef312010-07-21 18:54:22 +0000418 if (spec == EShSpecWebGL) {
419 if (identifier.substr(0, 6) == TString("webgl_")) {
420 error(line, reservedErrMsg, "webgl_", "");
421 return true;
422 }
423 if (identifier.substr(0, 7) == TString("_webgl_")) {
424 error(line, reservedErrMsg, "_webgl_", "");
425 return true;
426 }
427 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000428 if (identifier.find("__") != TString::npos) {
429 //error(line, "Two consecutive underscores are reserved for future use.", identifier.c_str(), "", "");
430 //return true;
431 infoSink.info.message(EPrefixWarning, "Two consecutive underscores are reserved for future use.", line);
432 return false;
433 }
434 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000436 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437}
438
439//
440// Make sure there is enough data provided to the constructor to build
441// something of the type of the constructor. Also returns the type of
442// the constructor.
443//
444// Returns true if there was an error in construction.
445//
446bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
447{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000448 *type = function.getReturnType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000450 bool constructingMatrix = false;
451 switch(op) {
452 case EOpConstructMat2:
453 case EOpConstructMat3:
454 case EOpConstructMat4:
455 constructingMatrix = true;
456 break;
457 default:
458 break;
459 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000461 //
462 // Note: It's okay to have too many components available, but not okay to have unused
463 // arguments. 'full' will go to true when enough args have been seen. If we loop
464 // again, there is an extra argument, so 'overfull' will become true.
465 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000467 int size = 0;
468 bool constType = true;
469 bool full = false;
470 bool overFull = false;
471 bool matrixInMatrix = false;
472 bool arrayArg = false;
473 for (int i = 0; i < function.getParamCount(); ++i) {
474 size += function[i].type->getObjectSize();
475
476 if (constructingMatrix && function[i].type->isMatrix())
477 matrixInMatrix = true;
478 if (full)
479 overFull = true;
480 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
481 full = true;
482 if (function[i].type->getQualifier() != EvqConst)
483 constType = false;
484 if (function[i].type->isArray())
485 arrayArg = true;
486 }
487
488 if (constType)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000489 type->setQualifier(EvqConst);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000491 if (type->isArray() && type->getArraySize() != function.getParamCount()) {
492 error(line, "array constructor needs one argument per array element", "constructor", "");
493 return true;
494 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000496 if (arrayArg && op != EOpConstructStruct) {
497 error(line, "constructing from a non-dereferenced array", "constructor", "");
498 return true;
499 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000500
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000501 if (matrixInMatrix && !type->isArray()) {
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000502 if (function.getParamCount() != 1) {
503 error(line, "constructing matrix from matrix can only take one argument", "constructor", "");
504 return true;
505 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000506 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000508 if (overFull) {
509 error(line, "too many arguments", "constructor", "");
510 return true;
511 }
512
513 if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->size() != function.getParamCount()) {
514 error(line, "Number of constructor parameters does not match the number of structure fields", "constructor", "");
515 return true;
516 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517
daniel@transgaming.combef0b6d2010-04-29 03:32:39 +0000518 if (!type->isMatrix()) {
519 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
520 (op == EOpConstructStruct && size < type->getObjectSize())) {
521 error(line, "not enough data provided for construction", "constructor", "");
522 return true;
523 }
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000524 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000525
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000526 TIntermTyped* typed = node->getAsTyped();
527 if (typed == 0) {
528 error(line, "constructor argument does not have a type", "constructor", "");
529 return true;
530 }
531 if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
532 error(line, "cannot convert a sampler", "constructor", "");
533 return true;
534 }
535 if (typed->getBasicType() == EbtVoid) {
536 error(line, "cannot convert a void", "constructor", "");
537 return true;
538 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000539
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000540 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541}
542
543// This function checks to see if a void variable has been declared and raise an error message for such a case
544//
545// returns true in case of an error
546//
547bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType)
548{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000549 if (pubType.type == EbtVoid) {
550 error(line, "illegal use of type 'void'", identifier.c_str(), "");
551 return true;
552 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000553
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000554 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000555}
556
557// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
558//
559// returns true in case of an error
560//
561bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type)
562{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000563 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
564 error(line, "boolean expression expected", "", "");
565 return true;
566 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000567
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000568 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569}
570
571// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
572//
573// returns true in case of an error
574//
575bool TParseContext::boolErrorCheck(int line, const TPublicType& pType)
576{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000577 if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
578 error(line, "boolean expression expected", "", "");
579 return true;
580 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000581
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000582 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583}
584
585bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason)
586{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000587 if (pType.type == EbtStruct) {
588 if (containsSampler(*pType.userDef)) {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000589 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000590
591 return true;
592 }
593
594 return false;
595 } else if (IsSampler(pType.type)) {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000596 error(line, reason, getBasicString(pType.type), "");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000598 return true;
599 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000601 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000602}
603
604bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
605{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000606 if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
607 pType.type == EbtStruct) {
608 error(line, "cannot be used with a structure", getQualifierString(pType.qualifier), "");
609
610 return true;
611 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000613 if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
614 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000615
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000616 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000617}
618
619bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
620{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000621 if ((qualifier == EvqOut || qualifier == EvqInOut) &&
622 type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
623 error(line, "samplers cannot be output parameters", type.getBasicString(), "");
624 return true;
625 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000627 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628}
629
630bool TParseContext::containsSampler(TType& type)
631{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000632 if (IsSampler(type.getBasicType()))
633 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000635 if (type.getBasicType() == EbtStruct) {
636 TTypeList& structure = *type.getStruct();
637 for (unsigned int i = 0; i < structure.size(); ++i) {
638 if (containsSampler(*structure[i].type))
639 return true;
640 }
641 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000643 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644}
645
646//
647// Do size checking for an array type's size.
648//
649// Returns true if there was an error.
650//
651bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
652{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000653 TIntermConstantUnion* constant = expr->getAsConstantUnion();
654 if (constant == 0 || constant->getBasicType() != EbtInt) {
655 error(line, "array size must be a constant integer expression", "", "");
656 return true;
657 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000659 size = constant->getUnionArrayPointer()->getIConst();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000661 if (size <= 0) {
662 error(line, "array size must be a positive integer", "", "");
663 size = 1;
664 return true;
665 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000666
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000667 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668}
669
670//
671// See if this qualifier can be an array.
672//
673// Returns true if there is an error.
674//
675bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
676{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000677 if (type.qualifier == EvqAttribute) {
678 error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), "");
679 return true;
680 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000681
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000682 if (type.qualifier == EvqConst && extensionErrorCheck(line, "GL_3DL_array_objects"))
683 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000685 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686}
687
688//
689// See if this type can be an array.
690//
691// Returns true if there is an error.
692//
693bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type)
694{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000695 //
696 // Can the type be an array?
697 //
698 if (type.array) {
699 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str(), "");
700 return true;
701 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000703 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704}
705
706//
707// Do all the semantic checking for declaring an array, with and
708// without a size, and make the right changes to the symbol table.
709//
710// size == 0 means no specified size.
711//
712// Returns true if there was an error.
713//
714bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable)
715{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000716 //
717 // Don't check for reserved word use until after we know it's not in the symbol table,
718 // because reserved arrays can be redeclared.
719 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000720
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000721 bool builtIn = false;
722 bool sameScope = false;
723 TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
724 if (symbol == 0 || !sameScope) {
725 if (reservedErrorCheck(line, identifier))
726 return true;
727
728 variable = new TVariable(&identifier, TType(type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000729
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000730 if (type.arraySize)
731 variable->getType().setArraySize(type.arraySize);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000733 if (! symbolTable.insert(*variable)) {
734 delete variable;
735 error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str(), "");
736 return true;
737 }
738 } else {
739 if (! symbol->isVariable()) {
740 error(line, "variable expected", identifier.c_str(), "");
741 return true;
742 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000744 variable = static_cast<TVariable*>(symbol);
745 if (! variable->getType().isArray()) {
746 error(line, "redeclaring non-array as array", identifier.c_str(), "");
747 return true;
748 }
749 if (variable->getType().getArraySize() > 0) {
750 error(line, "redeclaration of array with size", identifier.c_str(), "");
751 return true;
752 }
753
754 if (! variable->getType().sameElementType(TType(type))) {
755 error(line, "redeclaration of array with a different type", identifier.c_str(), "");
756 return true;
757 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000758
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000759 TType* t = variable->getArrayInformationType();
760 while (t != 0) {
761 if (t->getMaxArraySize() > type.arraySize) {
762 error(line, "higher index value already used for the array", identifier.c_str(), "");
763 return true;
764 }
765 t->setArraySize(type.arraySize);
766 t = t->getArrayInformationType();
767 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000769 if (type.arraySize)
770 variable->getType().setArraySize(type.arraySize);
771 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000772
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000773 if (voidErrorCheck(line, identifier, type))
774 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000775
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000776 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000777}
778
779bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line)
780{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000781 bool builtIn = false;
782 TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn);
783 if (symbol == 0) {
784 error(line, " undeclared identifier", node->getSymbol().c_str(), "");
785 return true;
786 }
787 TVariable* variable = static_cast<TVariable*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000789 type->setArrayInformationType(variable->getArrayInformationType());
790 variable->updateArrayInformationType(type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000791
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000792 // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers
793 // its an error
794 if (node->getSymbol() == "gl_FragData") {
795 TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn);
796 if (fragData == 0) {
797 infoSink.info.message(EPrefixInternalError, "gl_MaxDrawBuffers not defined", line);
798 return true;
799 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000800
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000801 int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst();
802 if (fragDataValue <= size) {
803 error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers", "");
804 return true;
805 }
806 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000808 // we dont want to update the maxArraySize when this flag is not set, we just want to include this
809 // node type in the chain of node types so that its updated when a higher maxArraySize comes in.
810 if (!updateFlag)
811 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000813 size++;
814 variable->getType().setMaxArraySize(size);
815 type->setMaxArraySize(size);
816 TType* tt = type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000817
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000818 while(tt->getArrayInformationType() != 0) {
819 tt = tt->getArrayInformationType();
820 tt->setMaxArraySize(size);
821 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000822
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000823 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000824}
825
826//
827// Enforce non-initializer type/qualifier rules.
828//
829// Returns true if there was an error.
830//
831bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type)
832{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000833 //
834 // Make the qualifier make sense.
835 //
836 if (type.qualifier == EvqConst) {
837 type.qualifier = EvqTemporary;
838 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
839 return true;
840 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000841
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000842 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000843}
844
845//
846// Do semantic checking for a variable declaration that has no initializer,
847// and update the symbol table.
848//
849// Returns true if there was an error.
850//
851bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type)
852{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000853 if (reservedErrorCheck(line, identifier))
854 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000855
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000856 TVariable* variable = new TVariable(&identifier, TType(type));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000857
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000858 if (! symbolTable.insert(*variable)) {
859 error(line, "redefinition", variable->getName().c_str(), "");
860 delete variable;
861 return true;
862 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000863
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000864 if (voidErrorCheck(line, identifier, type))
865 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000866
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000867 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000868}
869
870bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
871{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000872 if (qualifier != EvqConst && qualifier != EvqTemporary) {
873 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), "");
874 return true;
875 }
876 if (qualifier == EvqConst && paramQualifier != EvqIn) {
877 error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
878 return true;
879 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000881 if (qualifier == EvqConst)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000882 type->setQualifier(EvqConstReadOnly);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000883 else
alokp@chromium.org58e54292010-08-24 21:40:03 +0000884 type->setQualifier(paramQualifier);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000885
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000886 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000887}
888
889bool TParseContext::extensionErrorCheck(int line, const char* extension)
890{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000891 if (extensionBehavior[extension] == EBhWarn) {
892 infoSink.info.message(EPrefixWarning, ("extension " + TString(extension) + " is being used").c_str(), line);
893 return false;
894 }
895 if (extensionBehavior[extension] == EBhDisable) {
896 error(line, "extension", extension, "is disabled");
897 return true;
898 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000899
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000900 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901}
902
903/////////////////////////////////////////////////////////////////////////////////
904//
905// Non-Errors.
906//
907/////////////////////////////////////////////////////////////////////////////////
908
909//
910// Look up a function name in the symbol table, and make sure it is a function.
911//
912// Return the function symbol if found, otherwise 0.
913//
914const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn)
915{
alokp@chromium.org0a576182010-08-09 17:16:27 +0000916 // First find by unmangled name to check whether the function name has been
917 // hidden by a variable name or struct typename.
918 const TSymbol* symbol = symbolTable.find(call->getName(), builtIn);
919 if (symbol == 0) {
920 symbol = symbolTable.find(call->getMangledName(), builtIn);
921 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922
alokp@chromium.org0a576182010-08-09 17:16:27 +0000923 if (symbol == 0) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000924 error(line, "no matching overloaded function found", call->getName().c_str(), "");
925 return 0;
926 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927
alokp@chromium.org0a576182010-08-09 17:16:27 +0000928 if (!symbol->isFunction()) {
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000929 error(line, "function name expected", call->getName().c_str(), "");
930 return 0;
931 }
alokp@chromium.org0a576182010-08-09 17:16:27 +0000932
933 return static_cast<const TFunction*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000934}
935
936//
937// Initializers show up in several places in the grammar. Have one set of
938// code to handle them here.
939//
940bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000941 TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000942{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000943 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000945 if (variable == 0) {
946 if (reservedErrorCheck(line, identifier))
947 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000948
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000949 if (voidErrorCheck(line, identifier, pType))
950 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000951
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000952 //
953 // add variable to symbol table
954 //
955 variable = new TVariable(&identifier, type);
956 if (! symbolTable.insert(*variable)) {
957 error(line, "redefinition", variable->getName().c_str(), "");
958 return true;
959 // don't delete variable, it's used by error recovery, and the pool
960 // pop will take care of the memory
961 }
962 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000963
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000964 //
965 // identifier must be of type constant, a global, or a temporary
966 //
967 TQualifier qualifier = variable->getType().getQualifier();
968 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
969 error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), "");
970 return true;
971 }
972 //
973 // test for and propagate constant
974 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000976 if (qualifier == EvqConst) {
977 if (qualifier != initializer->getType().getQualifier()) {
978 error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +0000979 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000980 return true;
981 }
982 if (type != initializer->getType()) {
983 error(line, " non-matching types for const initializer ",
984 variable->getType().getQualifierString(), "");
alokp@chromium.org58e54292010-08-24 21:40:03 +0000985 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000986 return true;
987 }
988 if (initializer->getAsConstantUnion()) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000989 ConstantUnion* unionArray = variable->getConstPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000990
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000991 if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
992 *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
993 } else {
994 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
995 }
996 } else if (initializer->getAsSymbolNode()) {
997 const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
998 const TVariable* tVar = static_cast<const TVariable*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001000 ConstantUnion* constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001001 variable->shareConstPointer(constArray);
1002 } else {
1003 error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
alokp@chromium.org58e54292010-08-24 21:40:03 +00001004 variable->getType().setQualifier(EvqTemporary);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001005 return true;
1006 }
1007 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001009 if (qualifier != EvqConst) {
1010 TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
1011 intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
1012 if (intermNode == 0) {
1013 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1014 return true;
1015 }
1016 } else
1017 intermNode = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001018
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001019 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001020}
1021
1022bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
1023{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001024 if (!aggrNode->isConstructor())
1025 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001026
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001027 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001028
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001029 // check if all the child nodes are constants so that they can be inserted into
1030 // the parent node
1031 if (aggrNode) {
1032 TIntermSequence &childSequenceVector = aggrNode->getSequence() ;
1033 for (TIntermSequence::iterator p = childSequenceVector.begin();
1034 p != childSequenceVector.end(); p++) {
1035 if (!(*p)->getAsTyped()->getAsConstantUnion())
1036 return false;
1037 }
1038 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001039
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001040 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001041}
1042
1043// This function is used to test for the correctness of the parameters passed to various constructor functions
1044// and also convert them to the right datatype if it is allowed and required.
1045//
1046// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
1047//
1048TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
1049{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001050 if (node == 0)
1051 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001052
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001053 TIntermAggregate* aggrNode = node->getAsAggregate();
1054
alokp@chromium.org58e54292010-08-24 21:40:03 +00001055 TTypeList::const_iterator memberTypes;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001056 if (op == EOpConstructStruct)
1057 memberTypes = type->getStruct()->begin();
1058
1059 TType elementType = *type;
1060 if (type->isArray())
1061 elementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001063 bool singleArg;
1064 if (aggrNode) {
1065 if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
1066 singleArg = true;
1067 else
1068 singleArg = false;
1069 } else
1070 singleArg = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001071
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001072 TIntermTyped *newNode;
1073 if (singleArg) {
1074 // If structure constructor or array constructor is being called
1075 // for only one parameter inside the structure, we need to call constructStruct function once.
1076 if (type->isArray())
1077 newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
1078 else if (op == EOpConstructStruct)
1079 newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false);
1080 else
1081 newNode = constructBuiltIn(type, op, node, node->getLine(), false);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001083 if (newNode && newNode->getAsAggregate()) {
1084 TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
1085 if (constConstructor)
1086 return constConstructor;
1087 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001089 return newNode;
1090 }
1091
1092 //
1093 // Handle list of arguments.
1094 //
1095 TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
1096 // if the structure constructor contains more than one parameter, then construct
1097 // each parameter
1098
1099 int paramCount = 0; // keeps a track of the constructor parameter number being checked
1100
1101 // for each parameter to the constructor call, check to see if the right type is passed or convert them
1102 // to the right type if possible (and allowed).
1103 // for structure constructors, just check if the right type is passed, no conversion is allowed.
1104
1105 for (TIntermSequence::iterator p = sequenceVector.begin();
1106 p != sequenceVector.end(); p++, paramCount++) {
1107 if (type->isArray())
1108 newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
1109 else if (op == EOpConstructStruct)
1110 newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true);
1111 else
1112 newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
1113
1114 if (newNode) {
1115 *p = newNode;
1116 }
1117 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001119 TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
1120 TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
1121 if (constConstructor)
1122 return constConstructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001123
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001124 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001125}
1126
1127TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
1128{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001129 bool canBeFolded = areAllChildConst(aggrNode);
1130 aggrNode->setType(type);
1131 if (canBeFolded) {
1132 bool returnVal = false;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001133 ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001134 if (aggrNode->getSequence().size() == 1) {
1135 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
1136 }
1137 else {
1138 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
1139 }
1140 if (returnVal)
1141 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001142
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001143 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
1144 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001146 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147}
1148
1149// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
1150// for the parameter to the constructor (passed to this function). Essentially, it converts
1151// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
1152// float, then float is converted to int.
1153//
1154// Returns 0 for an error or the constructed node.
1155//
1156TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset)
1157{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001158 TIntermTyped* newNode;
1159 TOperator basicOp;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001160
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001161 //
1162 // First, convert types as needed.
1163 //
1164 switch (op) {
1165 case EOpConstructVec2:
1166 case EOpConstructVec3:
1167 case EOpConstructVec4:
1168 case EOpConstructMat2:
1169 case EOpConstructMat3:
1170 case EOpConstructMat4:
1171 case EOpConstructFloat:
1172 basicOp = EOpConstructFloat;
1173 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001174
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001175 case EOpConstructIVec2:
1176 case EOpConstructIVec3:
1177 case EOpConstructIVec4:
1178 case EOpConstructInt:
1179 basicOp = EOpConstructInt;
1180 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001181
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001182 case EOpConstructBVec2:
1183 case EOpConstructBVec3:
1184 case EOpConstructBVec4:
1185 case EOpConstructBool:
1186 basicOp = EOpConstructBool;
1187 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001188
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001189 default:
1190 error(line, "unsupported construction", "", "");
1191 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001192
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001193 return 0;
1194 }
1195 newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
1196 if (newNode == 0) {
1197 error(line, "can't convert", "constructor", "");
1198 return 0;
1199 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001200
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001201 //
1202 // Now, if there still isn't an operation to do the construction, and we need one, add one.
1203 //
1204
1205 // Otherwise, skip out early.
1206 if (subset || (newNode != node && newNode->getType() == *type))
1207 return newNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001209 // setAggregateOperator will insert a new node for the constructor, as needed.
1210 return intermediate.setAggregateOperator(newNode, op, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211}
1212
1213// This function tests for the type of the parameters to the structures constructors. Raises
1214// an error message if the expected type does not match the parameter passed to the constructor.
1215//
1216// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
1217//
1218TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset)
1219{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001220 if (*type == node->getAsTyped()->getType()) {
1221 if (subset)
1222 return node->getAsTyped();
1223 else
1224 return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
1225 } else {
1226 error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount,
1227 node->getAsTyped()->getType().getBasicString(), type->getBasicString());
1228 recover();
1229 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001231 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001232}
1233
1234//
1235// This function returns the tree representation for the vector field(s) being accessed from contant vector.
1236// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
1237// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
1238// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
1239// a constant matrix.
1240//
1241TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line)
1242{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001243 TIntermTyped* typedNode;
1244 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001245
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001246 ConstantUnion *unionArray;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001247 if (tempConstantNode) {
1248 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001249
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001250 if (!unionArray) { // this error message should never be raised
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001251 infoSink.info.message(EPrefixInternalError, "ConstantUnion not initialized in addConstVectorNode function", line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001252 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001253
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001254 return node;
1255 }
1256 } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
1257 error(line, "Cannot offset into the vector", "Error", "");
1258 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001260 return 0;
1261 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001262
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001263 ConstantUnion* constArray = new ConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001265 for (int i = 0; i < fields.num; i++) {
1266 if (fields.offsets[i] >= node->getType().getObjectSize()) {
1267 error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]);
1268 recover();
1269 fields.offsets[i] = 0;
1270 }
1271
1272 constArray[i] = unionArray[fields.offsets[i]];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001273
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001274 }
1275 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
1276 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277}
1278
1279//
1280// This function returns the column being accessed from a constant matrix. The values are retrieved from
1281// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
1282// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
1283// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
1284//
1285TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line)
1286{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001287 TIntermTyped* typedNode;
1288 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001289
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001290 if (index >= node->getType().getNominalSize()) {
1291 error(line, "", "[", "matrix field selection out of range '%d'", index);
1292 recover();
1293 index = 0;
1294 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001295
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001296 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001297 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001298 int size = tempConstantNode->getType().getNominalSize();
1299 typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
1300 } else {
1301 error(line, "Cannot offset into the matrix", "Error", "");
1302 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001303
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001304 return 0;
1305 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001306
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001307 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001308}
1309
1310
1311//
1312// This function returns an element of an array accessed from a constant array. The values are retrieved from
1313// the symbol table and parse-tree is built for the type of the element. The input
1314// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
1315// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
1316//
1317TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line)
1318{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001319 TIntermTyped* typedNode;
1320 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1321 TType arrayElementType = node->getType();
1322 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001323
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001324 if (index >= node->getType().getArraySize()) {
1325 error(line, "", "[", "array field selection out of range '%d'", index);
1326 recover();
1327 index = 0;
1328 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001329
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001330 int arrayElementSize = arrayElementType.getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001332 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001333 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001334 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
1335 } else {
1336 error(line, "Cannot offset into the array", "Error", "");
1337 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001338
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001339 return 0;
1340 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001341
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001342 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001343}
1344
1345
1346//
1347// This function returns the value of a particular field inside a constant structure from the symbol table.
1348// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
1349// function and returns the parse-tree with the values of the embedded/nested struct.
1350//
1351TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line)
1352{
alokp@chromium.org58e54292010-08-24 21:40:03 +00001353 const TTypeList* fields = node->getType().getStruct();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001354 TIntermTyped *typedNode;
1355 int instanceSize = 0;
1356 unsigned int index = 0;
1357 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001358
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001359 for ( index = 0; index < fields->size(); ++index) {
1360 if ((*fields)[index].type->getFieldName() == identifier) {
1361 break;
1362 } else {
1363 instanceSize += (*fields)[index].type->getObjectSize();
1364 }
1365 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001366
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001367 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001368 ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001369
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001370 typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
1371 } else {
1372 error(line, "Cannot offset into the structure", "Error", "");
1373 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001374
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001375 return 0;
1376 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001377
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001378 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001379}
1380
1381//
1382// Initialize all supported extensions to disable
1383//
1384void TParseContext::initializeExtensionBehavior()
1385{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001386 //
1387 // example code: extensionBehavior["test"] = EBhDisable; // where "test" is the name of
1388 // supported extension
1389 //
1390 extensionBehavior["GL_ARB_texture_rectangle"] = EBhRequire;
1391 extensionBehavior["GL_3DL_array_objects"] = EBhDisable;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001392}
1393
1394OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
1395
1396bool InitializeParseContextIndex()
1397{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001398 if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) {
1399 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1400 return false;
1401 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001402
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001403 //
1404 // Allocate a TLS index.
1405 //
1406 GlobalParseContextIndex = OS_AllocTLSIndex();
1407
1408 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1409 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1410 return false;
1411 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001412
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001413 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001414}
1415
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001416bool FreeParseContextIndex()
1417{
1418 OS_TLSIndex tlsiIndex = GlobalParseContextIndex;
1419
1420 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1421 assert(0 && "FreeParseContextIndex(): Parse Context index not initalised");
1422 return false;
1423 }
1424
1425 GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
1426
1427 return OS_FreeTLSIndex(tlsiIndex);
1428}
1429
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001430bool InitializeGlobalParseContext()
1431{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001432 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1433 assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised");
1434 return false;
1435 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001436
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001437 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
1438 if (lpParseContext != 0) {
1439 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1440 return false;
1441 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001442
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001443 TThreadParseContext *lpThreadData = new TThreadParseContext();
1444 if (lpThreadData == 0) {
1445 assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context");
1446 return false;
1447 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001448
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001449 lpThreadData->lpGlobalParseContext = 0;
1450 OS_SetTLSValue(GlobalParseContextIndex, lpThreadData);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001451
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001452 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001453}
1454
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001455bool FreeParseContext()
1456{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001457 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1458 assert(0 && "FreeParseContext(): Parse Context index not initalised");
1459 return false;
1460 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001461
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001462 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
1463 if (lpParseContext)
1464 delete lpParseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001465
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001466 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001467}
1468
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001469TParseContextPointer& GetGlobalParseContext()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001470{
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001471 //
1472 // Minimal error checking for speed
1473 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001474
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001475 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001476
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001477 return lpParseContext->lpGlobalParseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001478}
alokp@chromium.org34b99cd2010-07-27 18:37:55 +00001479