blob: f1ab572de4bd3599a870d525b1e1a78002e5de64 [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)
489 type->changeQualifier(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)) {
589 error(line, reason, TType::getBasicString(pType.type), "(structure contains a sampler)");
590
591 return true;
592 }
593
594 return false;
595 } else if (IsSampler(pType.type)) {
596 error(line, reason, TType::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)
882 type->changeQualifier(EvqConstReadOnly);
883 else
884 type->changeQualifier(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{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000916 const TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000917
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000918 if (symbol == 0) {
919 error(line, "no matching overloaded function found", call->getName().c_str(), "");
920 return 0;
921 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000923 if (! symbol->isFunction()) {
924 error(line, "function name expected", call->getName().c_str(), "");
925 return 0;
926 }
927
928 const TFunction* function = static_cast<const TFunction*>(symbol);
929
930 return function;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931}
932
933//
934// Initializers show up in several places in the grammar. Have one set of
935// code to handle them here.
936//
937bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000938 TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000939{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000940 TType type = TType(pType);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000941
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000942 if (variable == 0) {
943 if (reservedErrorCheck(line, identifier))
944 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000946 if (voidErrorCheck(line, identifier, pType))
947 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000948
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000949 //
950 // add variable to symbol table
951 //
952 variable = new TVariable(&identifier, type);
953 if (! symbolTable.insert(*variable)) {
954 error(line, "redefinition", variable->getName().c_str(), "");
955 return true;
956 // don't delete variable, it's used by error recovery, and the pool
957 // pop will take care of the memory
958 }
959 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000961 //
962 // identifier must be of type constant, a global, or a temporary
963 //
964 TQualifier qualifier = variable->getType().getQualifier();
965 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
966 error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), "");
967 return true;
968 }
969 //
970 // test for and propagate constant
971 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000972
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000973 if (qualifier == EvqConst) {
974 if (qualifier != initializer->getType().getQualifier()) {
975 error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
976 variable->getType().changeQualifier(EvqTemporary);
977 return true;
978 }
979 if (type != initializer->getType()) {
980 error(line, " non-matching types for const initializer ",
981 variable->getType().getQualifierString(), "");
982 variable->getType().changeQualifier(EvqTemporary);
983 return true;
984 }
985 if (initializer->getAsConstantUnion()) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000986 ConstantUnion* unionArray = variable->getConstPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000987
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000988 if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
989 *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
990 } else {
991 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
992 }
993 } else if (initializer->getAsSymbolNode()) {
994 const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
995 const TVariable* tVar = static_cast<const TVariable*>(symbol);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000996
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000997 ConstantUnion* constArray = tVar->getConstPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +0000998 variable->shareConstPointer(constArray);
999 } else {
1000 error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
1001 variable->getType().changeQualifier(EvqTemporary);
1002 return true;
1003 }
1004 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001005
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001006 if (qualifier != EvqConst) {
1007 TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
1008 intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
1009 if (intermNode == 0) {
1010 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1011 return true;
1012 }
1013 } else
1014 intermNode = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001015
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001016 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017}
1018
1019bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
1020{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001021 if (!aggrNode->isConstructor())
1022 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001023
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001024 bool allConstant = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001026 // check if all the child nodes are constants so that they can be inserted into
1027 // the parent node
1028 if (aggrNode) {
1029 TIntermSequence &childSequenceVector = aggrNode->getSequence() ;
1030 for (TIntermSequence::iterator p = childSequenceVector.begin();
1031 p != childSequenceVector.end(); p++) {
1032 if (!(*p)->getAsTyped()->getAsConstantUnion())
1033 return false;
1034 }
1035 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001037 return allConstant;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038}
1039
1040// This function is used to test for the correctness of the parameters passed to various constructor functions
1041// and also convert them to the right datatype if it is allowed and required.
1042//
1043// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
1044//
1045TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
1046{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001047 if (node == 0)
1048 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001050 TIntermAggregate* aggrNode = node->getAsAggregate();
1051
1052 TTypeList::iterator memberTypes;
1053 if (op == EOpConstructStruct)
1054 memberTypes = type->getStruct()->begin();
1055
1056 TType elementType = *type;
1057 if (type->isArray())
1058 elementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001059
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001060 bool singleArg;
1061 if (aggrNode) {
1062 if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
1063 singleArg = true;
1064 else
1065 singleArg = false;
1066 } else
1067 singleArg = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001069 TIntermTyped *newNode;
1070 if (singleArg) {
1071 // If structure constructor or array constructor is being called
1072 // for only one parameter inside the structure, we need to call constructStruct function once.
1073 if (type->isArray())
1074 newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
1075 else if (op == EOpConstructStruct)
1076 newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false);
1077 else
1078 newNode = constructBuiltIn(type, op, node, node->getLine(), false);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001080 if (newNode && newNode->getAsAggregate()) {
1081 TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
1082 if (constConstructor)
1083 return constConstructor;
1084 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001086 return newNode;
1087 }
1088
1089 //
1090 // Handle list of arguments.
1091 //
1092 TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
1093 // if the structure constructor contains more than one parameter, then construct
1094 // each parameter
1095
1096 int paramCount = 0; // keeps a track of the constructor parameter number being checked
1097
1098 // for each parameter to the constructor call, check to see if the right type is passed or convert them
1099 // to the right type if possible (and allowed).
1100 // for structure constructors, just check if the right type is passed, no conversion is allowed.
1101
1102 for (TIntermSequence::iterator p = sequenceVector.begin();
1103 p != sequenceVector.end(); p++, paramCount++) {
1104 if (type->isArray())
1105 newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
1106 else if (op == EOpConstructStruct)
1107 newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true);
1108 else
1109 newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
1110
1111 if (newNode) {
1112 *p = newNode;
1113 }
1114 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001116 TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
1117 TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
1118 if (constConstructor)
1119 return constConstructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001120
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001121 return constructor;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001122}
1123
1124TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
1125{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001126 bool canBeFolded = areAllChildConst(aggrNode);
1127 aggrNode->setType(type);
1128 if (canBeFolded) {
1129 bool returnVal = false;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001130 ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001131 if (aggrNode->getSequence().size() == 1) {
1132 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
1133 }
1134 else {
1135 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
1136 }
1137 if (returnVal)
1138 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001140 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
1141 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001142
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001143 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001144}
1145
1146// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
1147// for the parameter to the constructor (passed to this function). Essentially, it converts
1148// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
1149// float, then float is converted to int.
1150//
1151// Returns 0 for an error or the constructed node.
1152//
1153TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset)
1154{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001155 TIntermTyped* newNode;
1156 TOperator basicOp;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001157
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001158 //
1159 // First, convert types as needed.
1160 //
1161 switch (op) {
1162 case EOpConstructVec2:
1163 case EOpConstructVec3:
1164 case EOpConstructVec4:
1165 case EOpConstructMat2:
1166 case EOpConstructMat3:
1167 case EOpConstructMat4:
1168 case EOpConstructFloat:
1169 basicOp = EOpConstructFloat;
1170 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001171
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001172 case EOpConstructIVec2:
1173 case EOpConstructIVec3:
1174 case EOpConstructIVec4:
1175 case EOpConstructInt:
1176 basicOp = EOpConstructInt;
1177 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001178
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001179 case EOpConstructBVec2:
1180 case EOpConstructBVec3:
1181 case EOpConstructBVec4:
1182 case EOpConstructBool:
1183 basicOp = EOpConstructBool;
1184 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001186 default:
1187 error(line, "unsupported construction", "", "");
1188 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001189
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001190 return 0;
1191 }
1192 newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
1193 if (newNode == 0) {
1194 error(line, "can't convert", "constructor", "");
1195 return 0;
1196 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001197
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001198 //
1199 // Now, if there still isn't an operation to do the construction, and we need one, add one.
1200 //
1201
1202 // Otherwise, skip out early.
1203 if (subset || (newNode != node && newNode->getType() == *type))
1204 return newNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001206 // setAggregateOperator will insert a new node for the constructor, as needed.
1207 return intermediate.setAggregateOperator(newNode, op, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208}
1209
1210// This function tests for the type of the parameters to the structures constructors. Raises
1211// an error message if the expected type does not match the parameter passed to the constructor.
1212//
1213// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
1214//
1215TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset)
1216{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001217 if (*type == node->getAsTyped()->getType()) {
1218 if (subset)
1219 return node->getAsTyped();
1220 else
1221 return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
1222 } else {
1223 error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount,
1224 node->getAsTyped()->getType().getBasicString(), type->getBasicString());
1225 recover();
1226 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001227
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001228 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001229}
1230
1231//
1232// This function returns the tree representation for the vector field(s) being accessed from contant vector.
1233// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
1234// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
1235// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
1236// a constant matrix.
1237//
1238TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line)
1239{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001240 TIntermTyped* typedNode;
1241 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001243 ConstantUnion *unionArray;
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001244 if (tempConstantNode) {
1245 unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001246
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001247 if (!unionArray) { // this error message should never be raised
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001248 infoSink.info.message(EPrefixInternalError, "ConstantUnion not initialized in addConstVectorNode function", line);
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001249 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001251 return node;
1252 }
1253 } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
1254 error(line, "Cannot offset into the vector", "Error", "");
1255 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001256
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001257 return 0;
1258 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001260 ConstantUnion* constArray = new ConstantUnion[fields.num];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001262 for (int i = 0; i < fields.num; i++) {
1263 if (fields.offsets[i] >= node->getType().getObjectSize()) {
1264 error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]);
1265 recover();
1266 fields.offsets[i] = 0;
1267 }
1268
1269 constArray[i] = unionArray[fields.offsets[i]];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001270
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001271 }
1272 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
1273 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274}
1275
1276//
1277// This function returns the column being accessed from a constant matrix. The values are retrieved from
1278// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
1279// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
1280// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
1281//
1282TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line)
1283{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001284 TIntermTyped* typedNode;
1285 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001286
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001287 if (index >= node->getType().getNominalSize()) {
1288 error(line, "", "[", "matrix field selection out of range '%d'", index);
1289 recover();
1290 index = 0;
1291 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001292
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001293 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001294 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001295 int size = tempConstantNode->getType().getNominalSize();
1296 typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
1297 } else {
1298 error(line, "Cannot offset into the matrix", "Error", "");
1299 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001300
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001301 return 0;
1302 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001303
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001304 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001305}
1306
1307
1308//
1309// This function returns an element of an array accessed from a constant array. The values are retrieved from
1310// the symbol table and parse-tree is built for the type of the element. The input
1311// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
1312// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
1313//
1314TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line)
1315{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001316 TIntermTyped* typedNode;
1317 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1318 TType arrayElementType = node->getType();
1319 arrayElementType.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001320
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001321 if (index >= node->getType().getArraySize()) {
1322 error(line, "", "[", "array field selection out of range '%d'", index);
1323 recover();
1324 index = 0;
1325 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001326
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001327 int arrayElementSize = arrayElementType.getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001328
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001329 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001330 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001331 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
1332 } else {
1333 error(line, "Cannot offset into the array", "Error", "");
1334 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001335
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001336 return 0;
1337 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001338
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001339 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001340}
1341
1342
1343//
1344// This function returns the value of a particular field inside a constant structure from the symbol table.
1345// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
1346// function and returns the parse-tree with the values of the embedded/nested struct.
1347//
1348TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line)
1349{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001350 TTypeList* fields = node->getType().getStruct();
1351 TIntermTyped *typedNode;
1352 int instanceSize = 0;
1353 unsigned int index = 0;
1354 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001356 for ( index = 0; index < fields->size(); ++index) {
1357 if ((*fields)[index].type->getFieldName() == identifier) {
1358 break;
1359 } else {
1360 instanceSize += (*fields)[index].type->getObjectSize();
1361 }
1362 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001363
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001364 if (tempConstantNode) {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001365 ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001366
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001367 typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
1368 } else {
1369 error(line, "Cannot offset into the structure", "Error", "");
1370 recover();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001371
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001372 return 0;
1373 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001374
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001375 return typedNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001376}
1377
1378//
1379// Initialize all supported extensions to disable
1380//
1381void TParseContext::initializeExtensionBehavior()
1382{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001383 //
1384 // example code: extensionBehavior["test"] = EBhDisable; // where "test" is the name of
1385 // supported extension
1386 //
1387 extensionBehavior["GL_ARB_texture_rectangle"] = EBhRequire;
1388 extensionBehavior["GL_3DL_array_objects"] = EBhDisable;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001389}
1390
1391OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
1392
1393bool InitializeParseContextIndex()
1394{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001395 if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) {
1396 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1397 return false;
1398 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001399
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001400 //
1401 // Allocate a TLS index.
1402 //
1403 GlobalParseContextIndex = OS_AllocTLSIndex();
1404
1405 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1406 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1407 return false;
1408 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001409
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001410 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001411}
1412
1413bool InitializeGlobalParseContext()
1414{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001415 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1416 assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised");
1417 return false;
1418 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001419
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001420 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
1421 if (lpParseContext != 0) {
1422 assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
1423 return false;
1424 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001425
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001426 TThreadParseContext *lpThreadData = new TThreadParseContext();
1427 if (lpThreadData == 0) {
1428 assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context");
1429 return false;
1430 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001431
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001432 lpThreadData->lpGlobalParseContext = 0;
1433 OS_SetTLSValue(GlobalParseContextIndex, lpThreadData);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001434
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001435 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001436}
1437
1438TParseContextPointer& GetGlobalParseContext()
1439{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001440 //
1441 // Minimal error checking for speed
1442 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001443
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001444 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001445
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001446 return lpParseContext->lpGlobalParseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001447}
1448
1449bool FreeParseContext()
1450{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001451 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1452 assert(0 && "FreeParseContext(): Parse Context index not initalised");
1453 return false;
1454 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001455
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001456 TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
1457 if (lpParseContext)
1458 delete lpParseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001459
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001460 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001461}
1462
1463bool FreeParseContextIndex()
1464{
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001465 OS_TLSIndex tlsiIndex = GlobalParseContextIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001466
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001467 if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
1468 assert(0 && "FreeParseContextIndex(): Parse Context index not initalised");
1469 return false;
1470 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001472 GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001473
daniel@transgaming.comea15b0e2010-04-29 03:32:36 +00001474 return OS_FreeTLSIndex(tlsiIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001475}