1 //
2 // Copyright (c) 2002-2013 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
7 #include "compiler/translator/ParseContext.h"
8
9 #include <stdarg.h>
10 #include <stdio.h>
11
12 #include "compiler/translator/glslang.h"
13 #include "compiler/preprocessor/SourceLocation.h"
14
15 ///////////////////////////////////////////////////////////////////////
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 //
parseVectorFields(const TString & compString,int vecSize,TVectorFields & fields,const TSourceLoc & line)25 bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
26 {
27 fields.num = (int) compString.size();
28 if (fields.num > 4) {
29 error(line, "illegal vector field selection", compString.c_str());
30 return false;
31 }
32
33 enum {
34 exyzw,
35 ergba,
36 estpq
37 } fieldSet[4];
38
39 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 }
95
96 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 }
101
102 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 }
109
110 return true;
111 }
112
113
114 //
115 // Look at a '.' field selector string and change it into offsets
116 // for a matrix.
117 //
parseMatrixFields(const TString & compString,int matCols,int matRows,TMatrixFields & fields,const TSourceLoc & line)118 bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line)
119 {
120 fields.wholeRow = false;
121 fields.wholeCol = false;
122 fields.row = -1;
123 fields.col = -1;
124
125 if (compString.size() != 2) {
126 error(line, "illegal length of matrix field selection", compString.c_str());
127 return false;
128 }
129
130 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 }
153
154 if (fields.row >= matRows || fields.col >= matCols) {
155 error(line, "matrix field selection out of range", compString.c_str());
156 return false;
157 }
158
159 return true;
160 }
161
162 ///////////////////////////////////////////////////////////////////////
163 //
164 // Errors
165 //
166 ////////////////////////////////////////////////////////////////////////
167
168 //
169 // Track whether errors have occurred.
170 //
recover()171 void TParseContext::recover()
172 {
173 }
174
175 //
176 // Used by flex/bison to output all syntax and parsing errors.
177 //
error(const TSourceLoc & loc,const char * reason,const char * token,const char * extraInfo)178 void TParseContext::error(const TSourceLoc& loc,
179 const char* reason, const char* token,
180 const char* extraInfo)
181 {
182 pp::SourceLocation srcLoc;
183 srcLoc.file = loc.first_file;
184 srcLoc.line = loc.first_line;
185 diagnostics.writeInfo(pp::Diagnostics::PP_ERROR,
186 srcLoc, reason, token, extraInfo);
187
188 }
189
warning(const TSourceLoc & loc,const char * reason,const char * token,const char * extraInfo)190 void TParseContext::warning(const TSourceLoc& loc,
191 const char* reason, const char* token,
192 const char* extraInfo) {
193 pp::SourceLocation srcLoc;
194 srcLoc.file = loc.first_file;
195 srcLoc.line = loc.first_line;
196 diagnostics.writeInfo(pp::Diagnostics::PP_WARNING,
197 srcLoc, reason, token, extraInfo);
198 }
199
trace(const char * str)200 void TParseContext::trace(const char* str)
201 {
202 diagnostics.writeDebug(str);
203 }
204
205 //
206 // Same error message for all places assignments don't work.
207 //
assignError(const TSourceLoc & line,const char * op,TString left,TString right)208 void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
209 {
210 std::stringstream extraInfoStream;
211 extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
212 std::string extraInfo = extraInfoStream.str();
213 error(line, "", op, extraInfo.c_str());
214 }
215
216 //
217 // Same error message for all places unary operations don't work.
218 //
unaryOpError(const TSourceLoc & line,const char * op,TString operand)219 void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
220 {
221 std::stringstream extraInfoStream;
222 extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
223 << " (or there is no acceptable conversion)";
224 std::string extraInfo = extraInfoStream.str();
225 error(line, " wrong operand type", op, extraInfo.c_str());
226 }
227
228 //
229 // Same error message for all binary operations don't work.
230 //
binaryOpError(const TSourceLoc & line,const char * op,TString left,TString right)231 void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
232 {
233 std::stringstream extraInfoStream;
234 extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
235 << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
236 std::string extraInfo = extraInfoStream.str();
237 error(line, " wrong operand types ", op, extraInfo.c_str());
238 }
239
precisionErrorCheck(const TSourceLoc & line,TPrecision precision,TBasicType type)240 bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
241 if (!checksPrecisionErrors)
242 return false;
243 switch( type ){
244 case EbtFloat:
245 if( precision == EbpUndefined ){
246 error( line, "No precision specified for (float)", "" );
247 return true;
248 }
249 break;
250 case EbtInt:
251 if( precision == EbpUndefined ){
252 error( line, "No precision specified (int)", "" );
253 return true;
254 }
255 break;
256 default:
257 return false;
258 }
259 return false;
260 }
261
262 //
263 // Both test and if necessary, spit out an error, to see if the node is really
264 // an l-value that can be operated on this way.
265 //
266 // Returns true if the was an error.
267 //
lValueErrorCheck(const TSourceLoc & line,const char * op,TIntermTyped * node)268 bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
269 {
270 TIntermSymbol* symNode = node->getAsSymbolNode();
271 TIntermBinary* binaryNode = node->getAsBinaryNode();
272
273 if (binaryNode) {
274 bool errorReturn;
275
276 switch(binaryNode->getOp()) {
277 case EOpIndexDirect:
278 case EOpIndexIndirect:
279 case EOpIndexDirectStruct:
280 case EOpIndexDirectInterfaceBlock:
281 return lValueErrorCheck(line, op, binaryNode->getLeft());
282 case EOpVectorSwizzle:
283 errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
284 if (!errorReturn) {
285 int offset[4] = {0,0,0,0};
286
287 TIntermTyped* rightNode = binaryNode->getRight();
288 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
289
290 for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
291 p != aggrNode->getSequence().end(); p++) {
292 int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
293 offset[value]++;
294 if (offset[value] > 1) {
295 error(line, " l-value of swizzle cannot have duplicate components", op);
296
297 return true;
298 }
299 }
300 }
301
302 return errorReturn;
303 default:
304 break;
305 }
306 error(line, " l-value required", op);
307
308 return true;
309 }
310
311
312 const char* symbol = 0;
313 if (symNode != 0)
314 symbol = symNode->getSymbol().c_str();
315
316 const char* message = 0;
317 switch (node->getQualifier()) {
318 case EvqConst: message = "can't modify a const"; break;
319 case EvqConstReadOnly: message = "can't modify a const"; break;
320 case EvqAttribute: message = "can't modify an attribute"; break;
321 case EvqFragmentIn: message = "can't modify an input"; break;
322 case EvqVertexIn: message = "can't modify an input"; break;
323 case EvqUniform: message = "can't modify a uniform"; break;
324 case EvqVaryingIn: message = "can't modify a varying"; break;
325 case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
326 case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
327 case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
328 default:
329
330 //
331 // Type that can't be written to?
332 //
333 if (node->getBasicType() == EbtVoid) {
334 message = "can't modify void";
335 }
336 if (IsSampler(node->getBasicType())) {
337 message = "can't modify a sampler";
338 }
339 }
340
341 if (message == 0 && binaryNode == 0 && symNode == 0) {
342 error(line, " l-value required", op);
343
344 return true;
345 }
346
347
348 //
349 // Everything else is okay, no error.
350 //
351 if (message == 0)
352 return false;
353
354 //
355 // If we get here, we have an error and a message.
356 //
357 if (symNode) {
358 std::stringstream extraInfoStream;
359 extraInfoStream << "\"" << symbol << "\" (" << message << ")";
360 std::string extraInfo = extraInfoStream.str();
361 error(line, " l-value required", op, extraInfo.c_str());
362 }
363 else {
364 std::stringstream extraInfoStream;
365 extraInfoStream << "(" << message << ")";
366 std::string extraInfo = extraInfoStream.str();
367 error(line, " l-value required", op, extraInfo.c_str());
368 }
369
370 return true;
371 }
372
373 //
374 // Both test, and if necessary spit out an error, to see if the node is really
375 // a constant.
376 //
377 // Returns true if the was an error.
378 //
constErrorCheck(TIntermTyped * node)379 bool TParseContext::constErrorCheck(TIntermTyped* node)
380 {
381 if (node->getQualifier() == EvqConst)
382 return false;
383
384 error(node->getLine(), "constant expression required", "");
385
386 return true;
387 }
388
389 //
390 // Both test, and if necessary spit out an error, to see if the node is really
391 // an integer.
392 //
393 // Returns true if the was an error.
394 //
integerErrorCheck(TIntermTyped * node,const char * token)395 bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
396 {
397 if (node->isScalarInt())
398 return false;
399
400 error(node->getLine(), "integer expression required", token);
401
402 return true;
403 }
404
405 //
406 // Both test, and if necessary spit out an error, to see if we are currently
407 // globally scoped.
408 //
409 // Returns true if the was an error.
410 //
globalErrorCheck(const TSourceLoc & line,bool global,const char * token)411 bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
412 {
413 if (global)
414 return false;
415
416 error(line, "only allowed at global scope", token);
417
418 return true;
419 }
420
421 //
422 // For now, keep it simple: if it starts "gl_", it's reserved, independent
423 // of scope. Except, if the symbol table is at the built-in push-level,
424 // which is when we are parsing built-ins.
425 // Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
426 // webgl shader.
427 //
428 // Returns true if there was an error.
429 //
reservedErrorCheck(const TSourceLoc & line,const TString & identifier)430 bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
431 {
432 static const char* reservedErrMsg = "reserved built-in name";
433 if (!symbolTable.atBuiltInLevel()) {
434 if (identifier.compare(0, 3, "gl_") == 0) {
435 error(line, reservedErrMsg, "gl_");
436 return true;
437 }
438 if (IsWebGLBasedSpec(shaderSpec)) {
439 if (identifier.compare(0, 6, "webgl_") == 0) {
440 error(line, reservedErrMsg, "webgl_");
441 return true;
442 }
443 if (identifier.compare(0, 7, "_webgl_") == 0) {
444 error(line, reservedErrMsg, "_webgl_");
445 return true;
446 }
447 if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
448 error(line, reservedErrMsg, "css_");
449 return true;
450 }
451 }
452 if (identifier.find("__") != TString::npos) {
453 error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
454 return true;
455 }
456 }
457
458 return false;
459 }
460
461 //
462 // Make sure there is enough data provided to the constructor to build
463 // something of the type of the constructor. Also returns the type of
464 // the constructor.
465 //
466 // Returns true if there was an error in construction.
467 //
constructorErrorCheck(const TSourceLoc & line,TIntermNode * node,TFunction & function,TOperator op,TType * type)468 bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
469 {
470 *type = function.getReturnType();
471
472 bool constructingMatrix = false;
473 switch(op) {
474 case EOpConstructMat2:
475 case EOpConstructMat3:
476 case EOpConstructMat4:
477 constructingMatrix = true;
478 break;
479 default:
480 break;
481 }
482
483 //
484 // Note: It's okay to have too many components available, but not okay to have unused
485 // arguments. 'full' will go to true when enough args have been seen. If we loop
486 // again, there is an extra argument, so 'overfull' will become true.
487 //
488
489 size_t size = 0;
490 bool constType = true;
491 bool full = false;
492 bool overFull = false;
493 bool matrixInMatrix = false;
494 bool arrayArg = false;
495 for (size_t i = 0; i < function.getParamCount(); ++i) {
496 const TParameter& param = function.getParam(i);
497 size += param.type->getObjectSize();
498
499 if (constructingMatrix && param.type->isMatrix())
500 matrixInMatrix = true;
501 if (full)
502 overFull = true;
503 if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
504 full = true;
505 if (param.type->getQualifier() != EvqConst)
506 constType = false;
507 if (param.type->isArray())
508 arrayArg = true;
509 }
510
511 if (constType)
512 type->setQualifier(EvqConst);
513
514 if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
515 error(line, "array constructor needs one argument per array element", "constructor");
516 return true;
517 }
518
519 if (arrayArg && op != EOpConstructStruct) {
520 error(line, "constructing from a non-dereferenced array", "constructor");
521 return true;
522 }
523
524 if (matrixInMatrix && !type->isArray()) {
525 if (function.getParamCount() != 1) {
526 error(line, "constructing matrix from matrix can only take one argument", "constructor");
527 return true;
528 }
529 }
530
531 if (overFull) {
532 error(line, "too many arguments", "constructor");
533 return true;
534 }
535
536 if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) {
537 error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
538 return true;
539 }
540
541 if (!type->isMatrix() || !matrixInMatrix) {
542 if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
543 (op == EOpConstructStruct && size < type->getObjectSize())) {
544 error(line, "not enough data provided for construction", "constructor");
545 return true;
546 }
547 }
548
549 TIntermTyped *typed = node ? node->getAsTyped() : 0;
550 if (typed == 0) {
551 error(line, "constructor argument does not have a type", "constructor");
552 return true;
553 }
554 if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
555 error(line, "cannot convert a sampler", "constructor");
556 return true;
557 }
558 if (typed->getBasicType() == EbtVoid) {
559 error(line, "cannot convert a void", "constructor");
560 return true;
561 }
562
563 return false;
564 }
565
566 // This function checks to see if a void variable has been declared and raise an error message for such a case
567 //
568 // returns true in case of an error
569 //
voidErrorCheck(const TSourceLoc & line,const TString & identifier,const TPublicType & pubType)570 bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType)
571 {
572 if (pubType.type == EbtVoid) {
573 error(line, "illegal use of type 'void'", identifier.c_str());
574 return true;
575 }
576
577 return false;
578 }
579
580 // This function checks to see if the node (for the expression) contains a scalar boolean expression or not
581 //
582 // returns true in case of an error
583 //
boolErrorCheck(const TSourceLoc & line,const TIntermTyped * type)584 bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
585 {
586 if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
587 error(line, "boolean expression expected", "");
588 return true;
589 }
590
591 return false;
592 }
593
594 // This function checks to see if the node (for the expression) contains a scalar boolean expression or not
595 //
596 // returns true in case of an error
597 //
boolErrorCheck(const TSourceLoc & line,const TPublicType & pType)598 bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
599 {
600 if (pType.type != EbtBool || pType.isAggregate()) {
601 error(line, "boolean expression expected", "");
602 return true;
603 }
604
605 return false;
606 }
607
samplerErrorCheck(const TSourceLoc & line,const TPublicType & pType,const char * reason)608 bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
609 {
610 if (pType.type == EbtStruct) {
611 if (containsSampler(*pType.userDef)) {
612 error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
613
614 return true;
615 }
616
617 return false;
618 } else if (IsSampler(pType.type)) {
619 error(line, reason, getBasicString(pType.type));
620
621 return true;
622 }
623
624 return false;
625 }
626
structQualifierErrorCheck(const TSourceLoc & line,const TPublicType & pType)627 bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
628 {
629 switch (pType.qualifier)
630 {
631 case EvqVaryingIn:
632 case EvqVaryingOut:
633 case EvqAttribute:
634 case EvqVertexIn:
635 case EvqFragmentOut:
636 if (pType.type == EbtStruct)
637 {
638 error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
639 return true;
640 }
641
642 default: break;
643 }
644
645 if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
646 return true;
647
648 return false;
649 }
650
locationDeclaratorListCheck(const TSourceLoc & line,const TPublicType & pType)651 bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
652 {
653 if (pType.layoutQualifier.location != -1)
654 {
655 error(line, "location must only be specified for a single input or output variable", "location");
656 return true;
657 }
658
659 return false;
660 }
661
parameterSamplerErrorCheck(const TSourceLoc & line,TQualifier qualifier,const TType & type)662 bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
663 {
664 if ((qualifier == EvqOut || qualifier == EvqInOut) &&
665 type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
666 error(line, "samplers cannot be output parameters", type.getBasicString());
667 return true;
668 }
669
670 return false;
671 }
672
containsSampler(TType & type)673 bool TParseContext::containsSampler(TType& type)
674 {
675 if (IsSampler(type.getBasicType()))
676 return true;
677
678 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
679 const TFieldList& fields = type.getStruct()->fields();
680 for (unsigned int i = 0; i < fields.size(); ++i) {
681 if (containsSampler(*fields[i]->type()))
682 return true;
683 }
684 }
685
686 return false;
687 }
688
689 //
690 // Do size checking for an array type's size.
691 //
692 // Returns true if there was an error.
693 //
arraySizeErrorCheck(const TSourceLoc & line,TIntermTyped * expr,int & size)694 bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
695 {
696 TIntermConstantUnion* constant = expr->getAsConstantUnion();
697
698 if (constant == 0 || !constant->isScalarInt())
699 {
700 error(line, "array size must be a constant integer expression", "");
701 return true;
702 }
703
704 unsigned int unsignedSize = 0;
705
706 if (constant->getBasicType() == EbtUInt)
707 {
708 unsignedSize = constant->getUConst(0);
709 size = static_cast<int>(unsignedSize);
710 }
711 else
712 {
713 size = constant->getIConst(0);
714
715 if (size < 0)
716 {
717 error(line, "array size must be non-negative", "");
718 size = 1;
719 return true;
720 }
721
722 unsignedSize = static_cast<unsigned int>(size);
723 }
724
725 if (size == 0)
726 {
727 error(line, "array size must be greater than zero", "");
728 size = 1;
729 return true;
730 }
731
732 // The size of arrays is restricted here to prevent issues further down the
733 // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to
734 // 4096 registers so this should be reasonable even for aggressively optimizable code.
735 const unsigned int sizeLimit = 65536;
736
737 if (unsignedSize > sizeLimit)
738 {
739 error(line, "array size too large", "");
740 size = 1;
741 return true;
742 }
743
744 return false;
745 }
746
747 //
748 // See if this qualifier can be an array.
749 //
750 // Returns true if there is an error.
751 //
arrayQualifierErrorCheck(const TSourceLoc & line,TPublicType type)752 bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type)
753 {
754 if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConst)) {
755 error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
756 return true;
757 }
758
759 return false;
760 }
761
762 //
763 // See if this type can be an array.
764 //
765 // Returns true if there is an error.
766 //
arrayTypeErrorCheck(const TSourceLoc & line,TPublicType type)767 bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
768 {
769 //
770 // Can the type be an array?
771 //
772 if (type.array) {
773 error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
774 return true;
775 }
776
777 return false;
778 }
779
780 //
781 // Do all the semantic checking for declaring an array, with and
782 // without a size, and make the right changes to the symbol table.
783 //
784 // size == 0 means no specified size.
785 //
786 // Returns true if there was an error.
787 //
arrayErrorCheck(const TSourceLoc & line,const TString & identifier,const TPublicType & type,TVariable * & variable)788 bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable)
789 {
790 //
791 // Don't check for reserved word use until after we know it's not in the symbol table,
792 // because reserved arrays can be redeclared.
793 //
794
795 bool builtIn = false;
796 bool sameScope = false;
797 TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope);
798 if (symbol == 0 || !sameScope) {
799 if (reservedErrorCheck(line, identifier))
800 return true;
801
802 variable = new TVariable(&identifier, TType(type));
803
804 if (type.arraySize)
805 variable->getType().setArraySize(type.arraySize);
806
807 if (! symbolTable.declare(*variable)) {
808 delete variable;
809 error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
810 return true;
811 }
812 } else {
813 if (! symbol->isVariable()) {
814 error(line, "variable expected", identifier.c_str());
815 return true;
816 }
817
818 variable = static_cast<TVariable*>(symbol);
819 if (! variable->getType().isArray()) {
820 error(line, "redeclaring non-array as array", identifier.c_str());
821 return true;
822 }
823 if (variable->getType().getArraySize() > 0) {
824 error(line, "redeclaration of array with size", identifier.c_str());
825 return true;
826 }
827
828 if (! variable->getType().sameElementType(TType(type))) {
829 error(line, "redeclaration of array with a different type", identifier.c_str());
830 return true;
831 }
832
833 if (type.arraySize)
834 variable->getType().setArraySize(type.arraySize);
835 }
836
837 if (voidErrorCheck(line, identifier, type))
838 return true;
839
840 return false;
841 }
842
843 //
844 // Enforce non-initializer type/qualifier rules.
845 //
846 // Returns true if there was an error.
847 //
nonInitConstErrorCheck(const TSourceLoc & line,const TString & identifier,TPublicType & type,bool array)848 bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array)
849 {
850 if (type.qualifier == EvqConst)
851 {
852 // Make the qualifier make sense.
853 type.qualifier = EvqTemporary;
854
855 if (array)
856 {
857 error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
858 }
859 else if (type.isStructureContainingArrays())
860 {
861 error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
862 }
863 else
864 {
865 error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
866 }
867
868 return true;
869 }
870
871 return false;
872 }
873
874 //
875 // Do semantic checking for a variable declaration that has no initializer,
876 // and update the symbol table.
877 //
878 // Returns true if there was an error.
879 //
nonInitErrorCheck(const TSourceLoc & line,const TString & identifier,const TPublicType & type,TVariable * & variable)880 bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable)
881 {
882 if (reservedErrorCheck(line, identifier))
883 recover();
884
885 variable = new TVariable(&identifier, TType(type));
886
887 if (! symbolTable.declare(*variable)) {
888 error(line, "redefinition", variable->getName().c_str());
889 delete variable;
890 variable = 0;
891 return true;
892 }
893
894 if (voidErrorCheck(line, identifier, type))
895 return true;
896
897 return false;
898 }
899
paramErrorCheck(const TSourceLoc & line,TQualifier qualifier,TQualifier paramQualifier,TType * type)900 bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
901 {
902 if (qualifier != EvqConst && qualifier != EvqTemporary) {
903 error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
904 return true;
905 }
906 if (qualifier == EvqConst && paramQualifier != EvqIn) {
907 error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
908 return true;
909 }
910
911 if (qualifier == EvqConst)
912 type->setQualifier(EvqConstReadOnly);
913 else
914 type->setQualifier(paramQualifier);
915
916 return false;
917 }
918
extensionErrorCheck(const TSourceLoc & line,const TString & extension)919 bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
920 {
921 const TExtensionBehavior& extBehavior = extensionBehavior();
922 TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
923 if (iter == extBehavior.end()) {
924 error(line, "extension", extension.c_str(), "is not supported");
925 return true;
926 }
927 // In GLSL ES, an extension's default behavior is "disable".
928 if (iter->second == EBhDisable || iter->second == EBhUndefined) {
929 error(line, "extension", extension.c_str(), "is disabled");
930 return true;
931 }
932 if (iter->second == EBhWarn) {
933 warning(line, "extension", extension.c_str(), "is being used");
934 return false;
935 }
936
937 return false;
938 }
939
singleDeclarationErrorCheck(TPublicType & publicType,const TSourceLoc & identifierLocation,const TString & identifier)940 bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
941 {
942 if (structQualifierErrorCheck(identifierLocation, publicType))
943 return true;
944
945 // check for layout qualifier issues
946 const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
947
948 if (layoutQualifier.matrixPacking != EmpUnspecified)
949 {
950 error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks");
951 return true;
952 }
953
954 if (layoutQualifier.blockStorage != EbsUnspecified)
955 {
956 error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks");
957 return true;
958 }
959
960 if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
961 {
962 return true;
963 }
964
965 return false;
966 }
967
layoutLocationErrorCheck(const TSourceLoc & location,const TLayoutQualifier & layoutQualifier)968 bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier)
969 {
970 if (layoutQualifier.location != -1)
971 {
972 error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
973 return true;
974 }
975
976 return false;
977 }
978
supportsExtension(const char * extension)979 bool TParseContext::supportsExtension(const char* extension)
980 {
981 const TExtensionBehavior& extbehavior = extensionBehavior();
982 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
983 return (iter != extbehavior.end());
984 }
985
isExtensionEnabled(const char * extension) const986 bool TParseContext::isExtensionEnabled(const char* extension) const
987 {
988 const TExtensionBehavior& extbehavior = extensionBehavior();
989 TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
990
991 if (iter == extbehavior.end())
992 {
993 return false;
994 }
995
996 return (iter->second == EBhEnable || iter->second == EBhRequire);
997 }
998
handleExtensionDirective(const TSourceLoc & loc,const char * extName,const char * behavior)999 void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior)
1000 {
1001 pp::SourceLocation srcLoc;
1002 srcLoc.file = loc.first_file;
1003 srcLoc.line = loc.first_line;
1004 directiveHandler.handleExtension(srcLoc, extName, behavior);
1005 }
1006
handlePragmaDirective(const TSourceLoc & loc,const char * name,const char * value)1007 void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value)
1008 {
1009 pp::SourceLocation srcLoc;
1010 srcLoc.file = loc.first_file;
1011 srcLoc.line = loc.first_line;
1012 directiveHandler.handlePragma(srcLoc, name, value);
1013 }
1014
1015 /////////////////////////////////////////////////////////////////////////////////
1016 //
1017 // Non-Errors.
1018 //
1019 /////////////////////////////////////////////////////////////////////////////////
1020
1021 //
1022 // Look up a function name in the symbol table, and make sure it is a function.
1023 //
1024 // Return the function symbol if found, otherwise 0.
1025 //
findFunction(const TSourceLoc & line,TFunction * call,int shaderVersion,bool * builtIn)1026 const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn)
1027 {
1028 // First find by unmangled name to check whether the function name has been
1029 // hidden by a variable name or struct typename.
1030 // If a function is found, check for one with a matching argument list.
1031 const TSymbol* symbol = symbolTable.find(call->getName(), shaderVersion, builtIn);
1032 if (symbol == 0 || symbol->isFunction()) {
1033 symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn);
1034 }
1035
1036 if (symbol == 0) {
1037 error(line, "no matching overloaded function found", call->getName().c_str());
1038 return 0;
1039 }
1040
1041 if (!symbol->isFunction()) {
1042 error(line, "function name expected", call->getName().c_str());
1043 return 0;
1044 }
1045
1046 return static_cast<const TFunction*>(symbol);
1047 }
1048
1049 //
1050 // Initializers show up in several places in the grammar. Have one set of
1051 // code to handle them here.
1052 //
executeInitializer(const TSourceLoc & line,const TString & identifier,TPublicType & pType,TIntermTyped * initializer,TIntermNode * & intermNode,TVariable * variable)1053 bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType,
1054 TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
1055 {
1056 TType type = TType(pType);
1057
1058 if (variable == 0) {
1059 if (reservedErrorCheck(line, identifier))
1060 return true;
1061
1062 if (voidErrorCheck(line, identifier, pType))
1063 return true;
1064
1065 //
1066 // add variable to symbol table
1067 //
1068 variable = new TVariable(&identifier, type);
1069 if (! symbolTable.declare(*variable)) {
1070 error(line, "redefinition", variable->getName().c_str());
1071 return true;
1072 // don't delete variable, it's used by error recovery, and the pool
1073 // pop will take care of the memory
1074 }
1075 }
1076
1077 //
1078 // identifier must be of type constant, a global, or a temporary
1079 //
1080 TQualifier qualifier = variable->getType().getQualifier();
1081 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
1082 error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
1083 return true;
1084 }
1085 //
1086 // test for and propagate constant
1087 //
1088
1089 if (qualifier == EvqConst) {
1090 if (qualifier != initializer->getType().getQualifier()) {
1091 std::stringstream extraInfoStream;
1092 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1093 std::string extraInfo = extraInfoStream.str();
1094 error(line, " assigning non-constant to", "=", extraInfo.c_str());
1095 variable->getType().setQualifier(EvqTemporary);
1096 return true;
1097 }
1098 if (type != initializer->getType()) {
1099 error(line, " non-matching types for const initializer ",
1100 variable->getType().getQualifierString());
1101 variable->getType().setQualifier(EvqTemporary);
1102 return true;
1103 }
1104 if (initializer->getAsConstantUnion()) {
1105 variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
1106 } else if (initializer->getAsSymbolNode()) {
1107 const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
1108 const TVariable* tVar = static_cast<const TVariable*>(symbol);
1109
1110 ConstantUnion* constArray = tVar->getConstPointer();
1111 variable->shareConstPointer(constArray);
1112 } else {
1113 std::stringstream extraInfoStream;
1114 extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
1115 std::string extraInfo = extraInfoStream.str();
1116 error(line, " cannot assign to", "=", extraInfo.c_str());
1117 variable->getType().setQualifier(EvqTemporary);
1118 return true;
1119 }
1120 }
1121
1122 if (qualifier != EvqConst) {
1123 TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
1124 intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
1125 if (intermNode == 0) {
1126 assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
1127 return true;
1128 }
1129 } else
1130 intermNode = 0;
1131
1132 return false;
1133 }
1134
areAllChildConst(TIntermAggregate * aggrNode)1135 bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
1136 {
1137 ASSERT(aggrNode != NULL);
1138 if (!aggrNode->isConstructor())
1139 return false;
1140
1141 bool allConstant = true;
1142
1143 // check if all the child nodes are constants so that they can be inserted into
1144 // the parent node
1145 TIntermSequence &sequence = aggrNode->getSequence() ;
1146 for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
1147 if (!(*p)->getAsTyped()->getAsConstantUnion())
1148 return false;
1149 }
1150
1151 return allConstant;
1152 }
1153
addFullySpecifiedType(TQualifier qualifier,TLayoutQualifier layoutQualifier,const TPublicType & typeSpecifier)1154 TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
1155 {
1156 TPublicType returnType = typeSpecifier;
1157 returnType.qualifier = qualifier;
1158 returnType.layoutQualifier = layoutQualifier;
1159
1160 if (typeSpecifier.array)
1161 {
1162 error(typeSpecifier.line, "not supported", "first-class array");
1163 recover();
1164 returnType.setArray(false);
1165 }
1166
1167 if (shaderVersion < 300)
1168 {
1169 if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1170 {
1171 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1172 recover();
1173 }
1174
1175 if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
1176 (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
1177 {
1178 error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
1179 recover();
1180 }
1181 }
1182 else
1183 {
1184 switch (qualifier)
1185 {
1186 case EvqSmoothIn:
1187 case EvqSmoothOut:
1188 case EvqVertexOut:
1189 case EvqFragmentIn:
1190 case EvqCentroidOut:
1191 case EvqCentroidIn:
1192 if (typeSpecifier.type == EbtBool)
1193 {
1194 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1195 recover();
1196 }
1197 if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
1198 {
1199 error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
1200 recover();
1201 }
1202 break;
1203
1204 case EvqVertexIn:
1205 case EvqFragmentOut:
1206 case EvqFlatIn:
1207 case EvqFlatOut:
1208 if (typeSpecifier.type == EbtBool)
1209 {
1210 error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
1211 recover();
1212 }
1213 break;
1214
1215 default: break;
1216 }
1217 }
1218
1219 return returnType;
1220 }
1221
parseSingleDeclaration(TPublicType & publicType,const TSourceLoc & identifierLocation,const TString & identifier)1222 TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
1223 {
1224 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
1225 TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
1226
1227 if (identifier != "")
1228 {
1229 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
1230 recover();
1231
1232 // this error check can mutate the type
1233 if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
1234 recover();
1235
1236 TVariable* variable = 0;
1237
1238 if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
1239 recover();
1240
1241 if (variable && symbol)
1242 {
1243 symbol->setId(variable->getUniqueId());
1244 }
1245 }
1246
1247 return aggregate;
1248 }
1249
parseSingleArrayDeclaration(TPublicType & publicType,const TSourceLoc & identifierLocation,const TString & identifier,const TSourceLoc & indexLocation,TIntermTyped * indexExpression)1250 TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression)
1251 {
1252 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
1253 recover();
1254
1255 // this error check can mutate the type
1256 if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
1257 recover();
1258
1259 if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
1260 {
1261 recover();
1262 }
1263
1264 TPublicType arrayType = publicType;
1265
1266 int size;
1267 if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
1268 {
1269 recover();
1270 }
1271 else
1272 {
1273 arrayType.setArray(true, size);
1274 }
1275
1276 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(arrayType), identifierLocation);
1277 TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
1278 TVariable* variable = 0;
1279
1280 if (arrayErrorCheck(identifierLocation, identifier, arrayType, variable))
1281 recover();
1282
1283 if (variable && symbol)
1284 {
1285 symbol->setId(variable->getUniqueId());
1286 }
1287
1288 return aggregate;
1289 }
1290
parseSingleInitDeclaration(TPublicType & publicType,const TSourceLoc & identifierLocation,const TString & identifier,const TSourceLoc & initLocation,TIntermTyped * initializer)1291 TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
1292 {
1293 if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
1294 recover();
1295
1296 TIntermNode* intermNode;
1297 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1298 {
1299 //
1300 // Build intermediate representation
1301 //
1302 return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL;
1303 }
1304 else
1305 {
1306 recover();
1307 return NULL;
1308 }
1309 }
1310
parseDeclarator(TPublicType & publicType,TIntermAggregate * aggregateDeclaration,TSymbol * identifierSymbol,const TSourceLoc & identifierLocation,const TString & identifier)1311 TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
1312 {
1313 if (publicType.type == EbtInvariant && !identifierSymbol)
1314 {
1315 error(identifierLocation, "undeclared identifier declared as invariant", identifier.c_str());
1316 recover();
1317 }
1318
1319 TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
1320 TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
1321
1322 if (structQualifierErrorCheck(identifierLocation, publicType))
1323 recover();
1324
1325 if (locationDeclaratorListCheck(identifierLocation, publicType))
1326 recover();
1327
1328 if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
1329 recover();
1330
1331 TVariable* variable = 0;
1332 if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
1333 recover();
1334 if (symbol && variable)
1335 symbol->setId(variable->getUniqueId());
1336
1337 return intermAggregate;
1338 }
1339
parseArrayDeclarator(TPublicType & publicType,const TSourceLoc & identifierLocation,const TString & identifier,const TSourceLoc & arrayLocation,TIntermNode * declaratorList,TIntermTyped * indexExpression)1340 TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression)
1341 {
1342 if (structQualifierErrorCheck(identifierLocation, publicType))
1343 recover();
1344
1345 if (locationDeclaratorListCheck(identifierLocation, publicType))
1346 recover();
1347
1348 if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
1349 recover();
1350
1351 if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
1352 {
1353 recover();
1354 }
1355 else if (indexExpression)
1356 {
1357 int size;
1358 if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
1359 recover();
1360 TPublicType arrayType(publicType);
1361 arrayType.setArray(true, size);
1362 TVariable* variable = NULL;
1363 if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
1364 recover();
1365 TType type = TType(arrayType);
1366 type.setArraySize(size);
1367
1368 return intermediate.growAggregate(declaratorList, intermediate.addSymbol(variable ? variable->getUniqueId() : 0, identifier, type, identifierLocation), identifierLocation);
1369 }
1370 else
1371 {
1372 TPublicType arrayType(publicType);
1373 arrayType.setArray(true);
1374 TVariable* variable = NULL;
1375 if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
1376 recover();
1377 }
1378
1379 return NULL;
1380 }
1381
parseInitDeclarator(TPublicType & publicType,TIntermAggregate * declaratorList,const TSourceLoc & identifierLocation,const TString & identifier,const TSourceLoc & initLocation,TIntermTyped * initializer)1382 TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
1383 {
1384 if (structQualifierErrorCheck(identifierLocation, publicType))
1385 recover();
1386
1387 if (locationDeclaratorListCheck(identifierLocation, publicType))
1388 recover();
1389
1390 TIntermNode* intermNode;
1391 if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
1392 {
1393 //
1394 // build the intermediate representation
1395 //
1396 if (intermNode)
1397 {
1398 return intermediate.growAggregate(declaratorList, intermNode, initLocation);
1399 }
1400 else
1401 {
1402 return declaratorList;
1403 }
1404 }
1405 else
1406 {
1407 recover();
1408 return NULL;
1409 }
1410 }
1411
parseGlobalLayoutQualifier(const TPublicType & typeQualifier)1412 void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
1413 {
1414 if (typeQualifier.qualifier != EvqUniform)
1415 {
1416 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
1417 recover();
1418 return;
1419 }
1420
1421 const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
1422 ASSERT(!layoutQualifier.isEmpty());
1423
1424 if (shaderVersion < 300)
1425 {
1426 error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
1427 recover();
1428 return;
1429 }
1430
1431 if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier))
1432 {
1433 recover();
1434 return;
1435 }
1436
1437 if (layoutQualifier.matrixPacking != EmpUnspecified)
1438 {
1439 defaultMatrixPacking = layoutQualifier.matrixPacking;
1440 }
1441
1442 if (layoutQualifier.blockStorage != EbsUnspecified)
1443 {
1444 defaultBlockStorage = layoutQualifier.blockStorage;
1445 }
1446 }
1447
addConstructorFunc(TPublicType publicType)1448 TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
1449 {
1450 TOperator op = EOpNull;
1451 if (publicType.userDef)
1452 {
1453 op = EOpConstructStruct;
1454 }
1455 else
1456 {
1457 switch (publicType.type)
1458 {
1459 case EbtFloat:
1460 if (publicType.isMatrix())
1461 {
1462 // TODO: non-square matrices
1463 switch(publicType.getCols())
1464 {
1465 case 2: op = EOpConstructMat2; break;
1466 case 3: op = EOpConstructMat3; break;
1467 case 4: op = EOpConstructMat4; break;
1468 }
1469 }
1470 else
1471 {
1472 switch(publicType.getNominalSize())
1473 {
1474 case 1: op = EOpConstructFloat; break;
1475 case 2: op = EOpConstructVec2; break;
1476 case 3: op = EOpConstructVec3; break;
1477 case 4: op = EOpConstructVec4; break;
1478 }
1479 }
1480 break;
1481
1482 case EbtInt:
1483 switch(publicType.getNominalSize())
1484 {
1485 case 1: op = EOpConstructInt; break;
1486 case 2: op = EOpConstructIVec2; break;
1487 case 3: op = EOpConstructIVec3; break;
1488 case 4: op = EOpConstructIVec4; break;
1489 }
1490 break;
1491
1492 case EbtUInt:
1493 switch(publicType.getNominalSize())
1494 {
1495 case 1: op = EOpConstructUInt; break;
1496 case 2: op = EOpConstructUVec2; break;
1497 case 3: op = EOpConstructUVec3; break;
1498 case 4: op = EOpConstructUVec4; break;
1499 }
1500 break;
1501
1502 case EbtBool:
1503 switch(publicType.getNominalSize())
1504 {
1505 case 1: op = EOpConstructBool; break;
1506 case 2: op = EOpConstructBVec2; break;
1507 case 3: op = EOpConstructBVec3; break;
1508 case 4: op = EOpConstructBVec4; break;
1509 }
1510 break;
1511
1512 default: break;
1513 }
1514
1515 if (op == EOpNull)
1516 {
1517 error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
1518 recover();
1519 publicType.type = EbtFloat;
1520 op = EOpConstructFloat;
1521 }
1522 }
1523
1524 TString tempString;
1525 TType type(publicType);
1526 return new TFunction(&tempString, type, op);
1527 }
1528
1529 // This function is used to test for the correctness of the parameters passed to various constructor functions
1530 // and also convert them to the right datatype if it is allowed and required.
1531 //
1532 // Returns 0 for an error or the constructed node (aggregate or typed) for no error.
1533 //
addConstructor(TIntermNode * node,const TType * type,TOperator op,TFunction * fnCall,const TSourceLoc & line)1534 TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line)
1535 {
1536 if (node == 0)
1537 return 0;
1538
1539 TIntermAggregate* aggrNode = node->getAsAggregate();
1540
1541 TFieldList::const_iterator memberTypes;
1542 if (op == EOpConstructStruct)
1543 memberTypes = type->getStruct()->fields().begin();
1544
1545 TType elementType = *type;
1546 if (type->isArray())
1547 elementType.clearArrayness();
1548
1549 bool singleArg;
1550 if (aggrNode) {
1551 if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
1552 singleArg = true;
1553 else
1554 singleArg = false;
1555 } else
1556 singleArg = true;
1557
1558 TIntermTyped *newNode;
1559 if (singleArg) {
1560 // If structure constructor or array constructor is being called
1561 // for only one parameter inside the structure, we need to call constructStruct function once.
1562 if (type->isArray())
1563 newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
1564 else if (op == EOpConstructStruct)
1565 newNode = constructStruct(node, (*memberTypes)->type(), 1, node->getLine(), false);
1566 else
1567 newNode = constructBuiltIn(type, op, node, node->getLine(), false);
1568
1569 if (newNode && newNode->getAsAggregate()) {
1570 TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
1571 if (constConstructor)
1572 return constConstructor;
1573 }
1574
1575 return newNode;
1576 }
1577
1578 //
1579 // Handle list of arguments.
1580 //
1581 TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
1582 // if the structure constructor contains more than one parameter, then construct
1583 // each parameter
1584
1585 int paramCount = 0; // keeps a track of the constructor parameter number being checked
1586
1587 // for each parameter to the constructor call, check to see if the right type is passed or convert them
1588 // to the right type if possible (and allowed).
1589 // for structure constructors, just check if the right type is passed, no conversion is allowed.
1590
1591 for (TIntermSequence::iterator p = sequenceVector.begin();
1592 p != sequenceVector.end(); p++, paramCount++) {
1593 if (type->isArray())
1594 newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
1595 else if (op == EOpConstructStruct)
1596 newNode = constructStruct(*p, (memberTypes[paramCount])->type(), paramCount+1, node->getLine(), true);
1597 else
1598 newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
1599
1600 if (newNode) {
1601 *p = newNode;
1602 }
1603 }
1604
1605 TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
1606 TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
1607 if (constConstructor)
1608 return constConstructor;
1609
1610 return constructor;
1611 }
1612
foldConstConstructor(TIntermAggregate * aggrNode,const TType & type)1613 TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
1614 {
1615 bool canBeFolded = areAllChildConst(aggrNode);
1616 aggrNode->setType(type);
1617 if (canBeFolded) {
1618 bool returnVal = false;
1619 ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
1620 if (aggrNode->getSequence().size() == 1) {
1621 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true);
1622 }
1623 else {
1624 returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type);
1625 }
1626 if (returnVal)
1627 return 0;
1628
1629 return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
1630 }
1631
1632 return 0;
1633 }
1634
1635 // Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
1636 // for the parameter to the constructor (passed to this function). Essentially, it converts
1637 // the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
1638 // float, then float is converted to int.
1639 //
1640 // Returns 0 for an error or the constructed node.
1641 //
constructBuiltIn(const TType * type,TOperator op,TIntermNode * node,const TSourceLoc & line,bool subset)1642 TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset)
1643 {
1644 TIntermTyped* newNode;
1645 TOperator basicOp;
1646
1647 //
1648 // First, convert types as needed.
1649 //
1650 switch (op) {
1651 case EOpConstructVec2:
1652 case EOpConstructVec3:
1653 case EOpConstructVec4:
1654 case EOpConstructMat2:
1655 case EOpConstructMat3:
1656 case EOpConstructMat4:
1657 case EOpConstructFloat:
1658 basicOp = EOpConstructFloat;
1659 break;
1660
1661 case EOpConstructIVec2:
1662 case EOpConstructIVec3:
1663 case EOpConstructIVec4:
1664 case EOpConstructInt:
1665 basicOp = EOpConstructInt;
1666 break;
1667
1668 case EOpConstructUVec2:
1669 case EOpConstructUVec3:
1670 case EOpConstructUVec4:
1671 case EOpConstructUInt:
1672 basicOp = EOpConstructUInt;
1673 break;
1674
1675 case EOpConstructBVec2:
1676 case EOpConstructBVec3:
1677 case EOpConstructBVec4:
1678 case EOpConstructBool:
1679 basicOp = EOpConstructBool;
1680 break;
1681
1682 default:
1683 error(line, "unsupported construction", "");
1684 recover();
1685
1686 return 0;
1687 }
1688 newNode = intermediate.addUnaryMath(basicOp, node, node->getLine());
1689 if (newNode == 0) {
1690 error(line, "can't convert", "constructor");
1691 return 0;
1692 }
1693
1694 //
1695 // Now, if there still isn't an operation to do the construction, and we need one, add one.
1696 //
1697
1698 // Otherwise, skip out early.
1699 if (subset || (newNode != node && newNode->getType() == *type))
1700 return newNode;
1701
1702 // setAggregateOperator will insert a new node for the constructor, as needed.
1703 return intermediate.setAggregateOperator(newNode, op, line);
1704 }
1705
1706 // This function tests for the type of the parameters to the structures constructors. Raises
1707 // an error message if the expected type does not match the parameter passed to the constructor.
1708 //
1709 // Returns 0 for an error or the input node itself if the expected and the given parameter types match.
1710 //
constructStruct(TIntermNode * node,TType * type,int paramCount,const TSourceLoc & line,bool subset)1711 TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset)
1712 {
1713 if (*type == node->getAsTyped()->getType()) {
1714 if (subset)
1715 return node->getAsTyped();
1716 else
1717 return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
1718 } else {
1719 std::stringstream extraInfoStream;
1720 extraInfoStream << "cannot convert parameter " << paramCount
1721 << " from '" << node->getAsTyped()->getType().getBasicString()
1722 << "' to '" << type->getBasicString() << "'";
1723 std::string extraInfo = extraInfoStream.str();
1724 error(line, "", "constructor", extraInfo.c_str());
1725 recover();
1726 }
1727
1728 return 0;
1729 }
1730
1731 //
1732 // This function returns the tree representation for the vector field(s) being accessed from contant vector.
1733 // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
1734 // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
1735 // node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
1736 // a constant matrix.
1737 //
addConstVectorNode(TVectorFields & fields,TIntermTyped * node,const TSourceLoc & line)1738 TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
1739 {
1740 TIntermTyped* typedNode;
1741 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1742
1743 ConstantUnion *unionArray;
1744 if (tempConstantNode) {
1745 unionArray = tempConstantNode->getUnionArrayPointer();
1746
1747 if (!unionArray) {
1748 return node;
1749 }
1750 } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
1751 error(line, "Cannot offset into the vector", "Error");
1752 recover();
1753
1754 return 0;
1755 }
1756
1757 ConstantUnion* constArray = new ConstantUnion[fields.num];
1758
1759 for (int i = 0; i < fields.num; i++) {
1760 if (fields.offsets[i] >= node->getType().getNominalSize()) {
1761 std::stringstream extraInfoStream;
1762 extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
1763 std::string extraInfo = extraInfoStream.str();
1764 error(line, "", "[", extraInfo.c_str());
1765 recover();
1766 fields.offsets[i] = 0;
1767 }
1768
1769 constArray[i] = unionArray[fields.offsets[i]];
1770
1771 }
1772 typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
1773 return typedNode;
1774 }
1775
1776 //
1777 // This function returns the column being accessed from a constant matrix. The values are retrieved from
1778 // the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
1779 // to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
1780 // constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
1781 //
addConstMatrixNode(int index,TIntermTyped * node,const TSourceLoc & line)1782 TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
1783 {
1784 TIntermTyped* typedNode;
1785 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1786
1787 if (index >= node->getType().getCols()) {
1788 std::stringstream extraInfoStream;
1789 extraInfoStream << "matrix field selection out of range '" << index << "'";
1790 std::string extraInfo = extraInfoStream.str();
1791 error(line, "", "[", extraInfo.c_str());
1792 recover();
1793 index = 0;
1794 }
1795
1796 if (tempConstantNode) {
1797 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
1798 int size = tempConstantNode->getType().getCols();
1799 typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
1800 } else {
1801 error(line, "Cannot offset into the matrix", "Error");
1802 recover();
1803
1804 return 0;
1805 }
1806
1807 return typedNode;
1808 }
1809
1810
1811 //
1812 // This function returns an element of an array accessed from a constant array. The values are retrieved from
1813 // the symbol table and parse-tree is built for the type of the element. The input
1814 // to the function could either be a symbol node (a[0] where a is a constant array)that represents a
1815 // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
1816 //
addConstArrayNode(int index,TIntermTyped * node,const TSourceLoc & line)1817 TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
1818 {
1819 TIntermTyped* typedNode;
1820 TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
1821 TType arrayElementType = node->getType();
1822 arrayElementType.clearArrayness();
1823
1824 if (index >= node->getType().getArraySize()) {
1825 std::stringstream extraInfoStream;
1826 extraInfoStream << "array field selection out of range '" << index << "'";
1827 std::string extraInfo = extraInfoStream.str();
1828 error(line, "", "[", extraInfo.c_str());
1829 recover();
1830 index = 0;
1831 }
1832
1833 if (tempConstantNode) {
1834 size_t arrayElementSize = arrayElementType.getObjectSize();
1835 ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
1836 typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
1837 } else {
1838 error(line, "Cannot offset into the array", "Error");
1839 recover();
1840
1841 return 0;
1842 }
1843
1844 return typedNode;
1845 }
1846
1847
1848 //
1849 // This function returns the value of a particular field inside a constant structure from the symbol table.
1850 // If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
1851 // function and returns the parse-tree with the values of the embedded/nested struct.
1852 //
addConstStruct(const TString & identifier,TIntermTyped * node,const TSourceLoc & line)1853 TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line)
1854 {
1855 const TFieldList& fields = node->getType().getStruct()->fields();
1856 size_t instanceSize = 0;
1857
1858 for (size_t index = 0; index < fields.size(); ++index) {
1859 if (fields[index]->name() == identifier) {
1860 break;
1861 } else {
1862 instanceSize += fields[index]->type()->getObjectSize();
1863 }
1864 }
1865
1866 TIntermTyped *typedNode;
1867 TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
1868 if (tempConstantNode) {
1869 ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
1870
1871 typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
1872 } else {
1873 error(line, "Cannot offset into the structure", "Error");
1874 recover();
1875
1876 return 0;
1877 }
1878
1879 return typedNode;
1880 }
1881
1882 //
1883 // Interface/uniform blocks
1884 //
addInterfaceBlock(const TPublicType & typeQualifier,const TSourceLoc & nameLine,const TString & blockName,TFieldList * fieldList,const TString * instanceName,const TSourceLoc & instanceLine,TIntermTyped * arrayIndex,const TSourceLoc & arrayIndexLine)1885 TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
1886 const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
1887 {
1888 if (reservedErrorCheck(nameLine, blockName))
1889 recover();
1890
1891 if (typeQualifier.qualifier != EvqUniform)
1892 {
1893 error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
1894 recover();
1895 }
1896
1897 TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
1898 if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier))
1899 {
1900 recover();
1901 }
1902
1903 if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
1904 {
1905 blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
1906 }
1907
1908 if (blockLayoutQualifier.blockStorage == EbsUnspecified)
1909 {
1910 blockLayoutQualifier.blockStorage = defaultBlockStorage;
1911 }
1912
1913 TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
1914 if (!symbolTable.declare(*blockNameSymbol)) {
1915 error(nameLine, "redefinition", blockName.c_str(), "interface block name");
1916 recover();
1917 }
1918
1919 // check for sampler types and apply layout qualifiers
1920 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
1921 TField* field = (*fieldList)[memberIndex];
1922 TType* fieldType = field->type();
1923 if (IsSampler(fieldType->getBasicType())) {
1924 error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
1925 recover();
1926 }
1927
1928 const TQualifier qualifier = fieldType->getQualifier();
1929 switch (qualifier)
1930 {
1931 case EvqGlobal:
1932 case EvqUniform:
1933 break;
1934 default:
1935 error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
1936 recover();
1937 break;
1938 }
1939
1940 // check layout qualifiers
1941 TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
1942 if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier))
1943 {
1944 recover();
1945 }
1946
1947 if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
1948 {
1949 error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
1950 recover();
1951 }
1952
1953 if (fieldLayoutQualifier.matrixPacking == EmpUnspecified)
1954 {
1955 fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
1956 }
1957 else if (!fieldType->isMatrix())
1958 {
1959 error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
1960 recover();
1961 }
1962
1963 fieldType->setLayoutQualifier(fieldLayoutQualifier);
1964 }
1965
1966 // add array index
1967 int arraySize = 0;
1968 if (arrayIndex != NULL)
1969 {
1970 if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize))
1971 recover();
1972 }
1973
1974 TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
1975 TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
1976
1977 TString symbolName = "";
1978 int symbolId = 0;
1979
1980 if (!instanceName)
1981 {
1982 // define symbols for the members of the interface block
1983 for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
1984 {
1985 TField* field = (*fieldList)[memberIndex];
1986 TType* fieldType = field->type();
1987
1988 // set parent pointer of the field variable
1989 fieldType->setInterfaceBlock(interfaceBlock);
1990
1991 TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
1992 fieldVariable->setQualifier(typeQualifier.qualifier);
1993
1994 if (!symbolTable.declare(*fieldVariable)) {
1995 error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
1996 recover();
1997 }
1998 }
1999 }
2000 else
2001 {
2002 // add a symbol for this interface block
2003 TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
2004 instanceTypeDef->setQualifier(typeQualifier.qualifier);
2005
2006 if (!symbolTable.declare(*instanceTypeDef)) {
2007 error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
2008 recover();
2009 }
2010
2011 symbolId = instanceTypeDef->getUniqueId();
2012 symbolName = instanceTypeDef->getName();
2013 }
2014
2015 TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
2016 aggregate->setOp(EOpDeclaration);
2017
2018 exitStructDeclaration();
2019 return aggregate;
2020 }
2021
enterStructDeclaration(const TSourceLoc & line,const TString & identifier)2022 bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
2023 {
2024 ++structNestingLevel;
2025
2026 // Embedded structure definitions are not supported per GLSL ES spec.
2027 // They aren't allowed in GLSL either, but we need to detect this here
2028 // so we don't rely on the GLSL compiler to catch it.
2029 if (structNestingLevel > 1) {
2030 error(line, "", "Embedded struct definitions are not allowed");
2031 return true;
2032 }
2033
2034 return false;
2035 }
2036
exitStructDeclaration()2037 void TParseContext::exitStructDeclaration()
2038 {
2039 --structNestingLevel;
2040 }
2041
2042 namespace {
2043
2044 const int kWebGLMaxStructNesting = 4;
2045
2046 } // namespace
2047
structNestingErrorCheck(const TSourceLoc & line,const TField & field)2048 bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
2049 {
2050 if (!IsWebGLBasedSpec(shaderSpec)) {
2051 return false;
2052 }
2053
2054 if (field.type()->getBasicType() != EbtStruct) {
2055 return false;
2056 }
2057
2058 // We're already inside a structure definition at this point, so add
2059 // one to the field's struct nesting.
2060 if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
2061 std::stringstream reasonStream;
2062 reasonStream << "Reference of struct type "
2063 << field.type()->getStruct()->name().c_str()
2064 << " exceeds maximum allowed nesting level of "
2065 << kWebGLMaxStructNesting;
2066 std::string reason = reasonStream.str();
2067 error(line, reason.c_str(), field.name().c_str(), "");
2068 return true;
2069 }
2070
2071 return false;
2072 }
2073
2074 //
2075 // Parse an array index expression
2076 //
addIndexExpression(TIntermTyped * baseExpression,const TSourceLoc & location,TIntermTyped * indexExpression)2077 TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
2078 {
2079 TIntermTyped *indexedExpression = NULL;
2080
2081 if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
2082 {
2083 if (baseExpression->getAsSymbolNode())
2084 {
2085 error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
2086 }
2087 else
2088 {
2089 error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
2090 }
2091 recover();
2092 }
2093
2094 if (indexExpression->getQualifier() == EvqConst)
2095 {
2096 int index = indexExpression->getAsConstantUnion()->getIConst(0);
2097 if (index < 0)
2098 {
2099 std::stringstream infoStream;
2100 infoStream << index;
2101 std::string info = infoStream.str();
2102 error(location, "negative index", info.c_str());
2103 recover();
2104 index = 0;
2105 }
2106 if (baseExpression->getType().getQualifier() == EvqConst)
2107 {
2108 if (baseExpression->isArray())
2109 {
2110 // constant folding for arrays
2111 indexedExpression = addConstArrayNode(index, baseExpression, location);
2112 }
2113 else if (baseExpression->isVector())
2114 {
2115 // constant folding for vectors
2116 TVectorFields fields;
2117 fields.num = 1;
2118 fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
2119 indexedExpression = addConstVectorNode(fields, baseExpression, location);
2120 }
2121 else if (baseExpression->isMatrix())
2122 {
2123 // constant folding for matrices
2124 indexedExpression = addConstMatrixNode(index, baseExpression, location);
2125 }
2126 }
2127 else
2128 {
2129 if (baseExpression->isArray())
2130 {
2131 if (index >= baseExpression->getType().getArraySize())
2132 {
2133 std::stringstream extraInfoStream;
2134 extraInfoStream << "array index out of range '" << index << "'";
2135 std::string extraInfo = extraInfoStream.str();
2136 error(location, "", "[", extraInfo.c_str());
2137 recover();
2138 index = baseExpression->getType().getArraySize() - 1;
2139 }
2140 else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
2141 {
2142 error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
2143 recover();
2144 index = 0;
2145 }
2146 }
2147 else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
2148 {
2149 std::stringstream extraInfoStream;
2150 extraInfoStream << "field selection out of range '" << index << "'";
2151 std::string extraInfo = extraInfoStream.str();
2152 error(location, "", "[", extraInfo.c_str());
2153 recover();
2154 index = baseExpression->getType().getNominalSize() - 1;
2155 }
2156
2157 indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index);
2158 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
2159 }
2160 }
2161 else
2162 {
2163 if (baseExpression->isInterfaceBlock())
2164 {
2165 error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions");
2166 recover();
2167 }
2168 else if (baseExpression->getQualifier() == EvqFragmentOut)
2169 {
2170 error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions");
2171 recover();
2172 }
2173
2174 indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
2175 }
2176
2177 if (indexedExpression == 0)
2178 {
2179 ConstantUnion *unionArray = new ConstantUnion[1];
2180 unionArray->setFConst(0.0f);
2181 indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
2182 }
2183 else if (baseExpression->isArray())
2184 {
2185 const TType &baseType = baseExpression->getType();
2186 if (baseType.getStruct())
2187 {
2188 TType copyOfType(baseType.getStruct());
2189 indexedExpression->setType(copyOfType);
2190 }
2191 else if (baseType.isInterfaceBlock())
2192 {
2193 TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0);
2194 indexedExpression->setType(copyOfType);
2195 }
2196 else
2197 {
2198 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->getSecondarySize()));
2199 }
2200
2201 if (baseExpression->getType().getQualifier() == EvqConst)
2202 {
2203 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2204 }
2205 }
2206 else if (baseExpression->isMatrix())
2207 {
2208 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2209 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getRows()));
2210 }
2211 else if (baseExpression->isVector())
2212 {
2213 TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
2214 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
2215 }
2216 else
2217 {
2218 indexedExpression->setType(baseExpression->getType());
2219 }
2220
2221 return indexedExpression;
2222 }
2223
addFieldSelectionExpression(TIntermTyped * baseExpression,const TSourceLoc & dotLocation,const TString & fieldString,const TSourceLoc & fieldLocation)2224 TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation)
2225 {
2226 TIntermTyped *indexedExpression = NULL;
2227
2228 if (baseExpression->isArray())
2229 {
2230 error(fieldLocation, "cannot apply dot operator to an array", ".");
2231 recover();
2232 }
2233
2234 if (baseExpression->isVector())
2235 {
2236 TVectorFields fields;
2237 if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation))
2238 {
2239 fields.num = 1;
2240 fields.offsets[0] = 0;
2241 recover();
2242 }
2243
2244 if (baseExpression->getType().getQualifier() == EvqConst)
2245 {
2246 // constant folding for vector fields
2247 indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
2248 if (indexedExpression == 0)
2249 {
2250 recover();
2251 indexedExpression = baseExpression;
2252 }
2253 else
2254 {
2255 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (int) (fieldString).size()));
2256 }
2257 }
2258 else
2259 {
2260 TString vectorString = fieldString;
2261 TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation);
2262 indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
2263 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (int) vectorString.size()));
2264 }
2265 }
2266 else if (baseExpression->isMatrix())
2267 {
2268 TMatrixFields fields;
2269 if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation))
2270 {
2271 fields.wholeRow = false;
2272 fields.wholeCol = false;
2273 fields.row = 0;
2274 fields.col = 0;
2275 recover();
2276 }
2277
2278 if (fields.wholeRow || fields.wholeCol)
2279 {
2280 error(dotLocation, " non-scalar fields not implemented yet", ".");
2281 recover();
2282 ConstantUnion *unionArray = new ConstantUnion[1];
2283 unionArray->setIConst(0);
2284 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2285 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
2286 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary, baseExpression->getCols(), baseExpression->getRows()));
2287 }
2288 else
2289 {
2290 ConstantUnion *unionArray = new ConstantUnion[1];
2291 unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
2292 TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
2293 indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
2294 indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
2295 }
2296 }
2297 else if (baseExpression->getBasicType() == EbtStruct)
2298 {
2299 bool fieldFound = false;
2300 const TFieldList& fields = baseExpression->getType().getStruct()->fields();
2301 if (fields.empty())
2302 {
2303 error(dotLocation, "structure has no fields", "Internal Error");
2304 recover();
2305 indexedExpression = baseExpression;
2306 }
2307 else
2308 {
2309 unsigned int i;
2310 for (i = 0; i < fields.size(); ++i)
2311 {
2312 if (fields[i]->name() == fieldString)
2313 {
2314 fieldFound = true;
2315 break;
2316 }
2317 }
2318 if (fieldFound)
2319 {
2320 if (baseExpression->getType().getQualifier() == EvqConst)
2321 {
2322 indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
2323 if (indexedExpression == 0)
2324 {
2325 recover();
2326 indexedExpression = baseExpression;
2327 }
2328 else
2329 {
2330 indexedExpression->setType(*fields[i]->type());
2331 // change the qualifier of the return type, not of the structure field
2332 // as the structure definition is shared between various structures.
2333 indexedExpression->getTypePointer()->setQualifier(EvqConst);
2334 }
2335 }
2336 else
2337 {
2338 ConstantUnion *unionArray = new ConstantUnion[1];
2339 unionArray->setIConst(i);
2340 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
2341 indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
2342 indexedExpression->setType(*fields[i]->type());
2343 }
2344 }
2345 else
2346 {
2347 error(dotLocation, " no such field in structure", fieldString.c_str());
2348 recover();
2349 indexedExpression = baseExpression;
2350 }
2351 }
2352 }
2353 else if (baseExpression->isInterfaceBlock())
2354 {
2355 bool fieldFound = false;
2356 const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields();
2357 if (fields.empty())
2358 {
2359 error(dotLocation, "interface block has no fields", "Internal Error");
2360 recover();
2361 indexedExpression = baseExpression;
2362 }
2363 else
2364 {
2365 unsigned int i;
2366 for (i = 0; i < fields.size(); ++i)
2367 {
2368 if (fields[i]->name() == fieldString)
2369 {
2370 fieldFound = true;
2371 break;
2372 }
2373 }
2374 if (fieldFound)
2375 {
2376 ConstantUnion *unionArray = new ConstantUnion[1];
2377 unionArray->setIConst(i);
2378 TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
2379 indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
2380 indexedExpression->setType(*fields[i]->type());
2381 }
2382 else
2383 {
2384 error(dotLocation, " no such field in interface block", fieldString.c_str());
2385 recover();
2386 indexedExpression = baseExpression;
2387 }
2388 }
2389 }
2390 else
2391 {
2392 if (shaderVersion < 300)
2393 {
2394 error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
2395 }
2396 else
2397 {
2398 error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
2399 }
2400 recover();
2401 indexedExpression = baseExpression;
2402 }
2403
2404 return indexedExpression;
2405 }
2406
parseLayoutQualifier(const TString & qualifierType,const TSourceLoc & qualifierTypeLine)2407 TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine)
2408 {
2409 TLayoutQualifier qualifier;
2410
2411 qualifier.location = -1;
2412 qualifier.matrixPacking = EmpUnspecified;
2413 qualifier.blockStorage = EbsUnspecified;
2414
2415 if (qualifierType == "shared")
2416 {
2417 qualifier.blockStorage = EbsShared;
2418 }
2419 else if (qualifierType == "packed")
2420 {
2421 qualifier.blockStorage = EbsPacked;
2422 }
2423 else if (qualifierType == "std140")
2424 {
2425 qualifier.blockStorage = EbsStd140;
2426 }
2427 else if (qualifierType == "row_major")
2428 {
2429 qualifier.matrixPacking = EmpRowMajor;
2430 }
2431 else if (qualifierType == "column_major")
2432 {
2433 qualifier.matrixPacking = EmpColumnMajor;
2434 }
2435 else if (qualifierType == "location")
2436 {
2437 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument");
2438 recover();
2439 }
2440 else
2441 {
2442 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
2443 recover();
2444 }
2445
2446 return qualifier;
2447 }
2448
parseLayoutQualifier(const TString & qualifierType,const TSourceLoc & qualifierTypeLine,const TString & intValueString,int intValue,const TSourceLoc & intValueLine)2449 TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine)
2450 {
2451 TLayoutQualifier qualifier;
2452
2453 qualifier.location = -1;
2454 qualifier.matrixPacking = EmpUnspecified;
2455 qualifier.blockStorage = EbsUnspecified;
2456
2457 if (qualifierType != "location")
2458 {
2459 error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments");
2460 recover();
2461 }
2462 else
2463 {
2464 // must check that location is non-negative
2465 if (intValue < 0)
2466 {
2467 error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
2468 recover();
2469 }
2470 else
2471 {
2472 qualifier.location = intValue;
2473 }
2474 }
2475
2476 return qualifier;
2477 }
2478
joinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier)2479 TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
2480 {
2481 TLayoutQualifier joinedQualifier = leftQualifier;
2482
2483 if (rightQualifier.location != -1)
2484 {
2485 joinedQualifier.location = rightQualifier.location;
2486 }
2487 if (rightQualifier.matrixPacking != EmpUnspecified)
2488 {
2489 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
2490 }
2491 if (rightQualifier.blockStorage != EbsUnspecified)
2492 {
2493 joinedQualifier.blockStorage = rightQualifier.blockStorage;
2494 }
2495
2496 return joinedQualifier;
2497 }
2498
joinInterpolationQualifiers(const TSourceLoc & interpolationLoc,TQualifier interpolationQualifier,const TSourceLoc & storageLoc,TQualifier storageQualifier)2499 TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
2500 const TSourceLoc &storageLoc, TQualifier storageQualifier)
2501 {
2502 TQualifier mergedQualifier = EvqSmoothIn;
2503
2504 if (storageQualifier == EvqFragmentIn) {
2505 if (interpolationQualifier == EvqSmooth)
2506 mergedQualifier = EvqSmoothIn;
2507 else if (interpolationQualifier == EvqFlat)
2508 mergedQualifier = EvqFlatIn;
2509 else UNREACHABLE();
2510 }
2511 else if (storageQualifier == EvqCentroidIn) {
2512 if (interpolationQualifier == EvqSmooth)
2513 mergedQualifier = EvqCentroidIn;
2514 else if (interpolationQualifier == EvqFlat)
2515 mergedQualifier = EvqFlatIn;
2516 else UNREACHABLE();
2517 }
2518 else if (storageQualifier == EvqVertexOut) {
2519 if (interpolationQualifier == EvqSmooth)
2520 mergedQualifier = EvqSmoothOut;
2521 else if (interpolationQualifier == EvqFlat)
2522 mergedQualifier = EvqFlatOut;
2523 else UNREACHABLE();
2524 }
2525 else if (storageQualifier == EvqCentroidOut) {
2526 if (interpolationQualifier == EvqSmooth)
2527 mergedQualifier = EvqCentroidOut;
2528 else if (interpolationQualifier == EvqFlat)
2529 mergedQualifier = EvqFlatOut;
2530 else UNREACHABLE();
2531 }
2532 else {
2533 error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier));
2534 recover();
2535
2536 mergedQualifier = storageQualifier;
2537 }
2538
2539 TPublicType type;
2540 type.setBasic(EbtVoid, mergedQualifier, storageLoc);
2541 return type;
2542 }
2543
addStructDeclaratorList(const TPublicType & typeSpecifier,TFieldList * fieldList)2544 TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList)
2545 {
2546 if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier)) {
2547 recover();
2548 }
2549
2550 for (unsigned int i = 0; i < fieldList->size(); ++i) {
2551 //
2552 // Careful not to replace already known aspects of type, like array-ness
2553 //
2554 TType* type = (*fieldList)[i]->type();
2555 type->setBasicType(typeSpecifier.type);
2556 type->setPrimarySize(typeSpecifier.primarySize);
2557 type->setSecondarySize(typeSpecifier.secondarySize);
2558 type->setPrecision(typeSpecifier.precision);
2559 type->setQualifier(typeSpecifier.qualifier);
2560 type->setLayoutQualifier(typeSpecifier.layoutQualifier);
2561
2562 // don't allow arrays of arrays
2563 if (type->isArray()) {
2564 if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
2565 recover();
2566 }
2567 if (typeSpecifier.array)
2568 type->setArraySize(typeSpecifier.arraySize);
2569 if (typeSpecifier.userDef) {
2570 type->setStruct(typeSpecifier.userDef->getStruct());
2571 }
2572
2573 if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) {
2574 recover();
2575 }
2576 }
2577
2578 return fieldList;
2579 }
2580
addStructure(const TSourceLoc & structLine,const TSourceLoc & nameLine,const TString * structName,TFieldList * fieldList)2581 TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList)
2582 {
2583 TStructure* structure = new TStructure(structName, fieldList);
2584 TType* structureType = new TType(structure);
2585
2586 structure->setUniqueId(TSymbolTable::nextUniqueId());
2587
2588 if (!structName->empty())
2589 {
2590 if (reservedErrorCheck(nameLine, *structName))
2591 {
2592 recover();
2593 }
2594 TVariable* userTypeDef = new TVariable(structName, *structureType, true);
2595 if (!symbolTable.declare(*userTypeDef)) {
2596 error(nameLine, "redefinition", structName->c_str(), "struct");
2597 recover();
2598 }
2599 }
2600
2601 // ensure we do not specify any storage qualifiers on the struct members
2602 for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
2603 {
2604 const TField &field = *(*fieldList)[typeListIndex];
2605 const TQualifier qualifier = field.type()->getQualifier();
2606 switch (qualifier)
2607 {
2608 case EvqGlobal:
2609 case EvqTemporary:
2610 break;
2611 default:
2612 error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
2613 recover();
2614 break;
2615 }
2616 }
2617
2618 TPublicType publicType;
2619 publicType.setBasic(EbtStruct, EvqTemporary, structLine);
2620 publicType.userDef = structureType;
2621 exitStructDeclaration();
2622
2623 return publicType;
2624 }
2625
2626 //
2627 // Parse an array of strings using yyparse.
2628 //
2629 // Returns 0 for success.
2630 //
PaParseStrings(size_t count,const char * const string[],const int length[],TParseContext * context)2631 int PaParseStrings(size_t count, const char* const string[], const int length[],
2632 TParseContext* context) {
2633 if ((count == 0) || (string == NULL))
2634 return 1;
2635
2636 if (glslang_initialize(context))
2637 return 1;
2638
2639 int error = glslang_scan(count, string, length, context);
2640 if (!error)
2641 error = glslang_parse(context);
2642
2643 glslang_finalize(context);
2644
2645 return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
2646 }
2647
2648
2649
2650