1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #include "ParseHelper.h" |
16 | |
17 | #include <limits> |
18 | #include <stdarg.h> |
19 | #include <stdio.h> |
20 | |
21 | #include "glslang.h" |
22 | #include "preprocessor/SourceLocation.h" |
23 | #include "ValidateSwitch.h" |
24 | |
25 | /////////////////////////////////////////////////////////////////////// |
26 | // |
27 | // Sub- vector and matrix fields |
28 | // |
29 | //////////////////////////////////////////////////////////////////////// |
30 | |
31 | namespace |
32 | { |
33 | bool IsVaryingOut(TQualifier qualifier) |
34 | { |
35 | switch(qualifier) |
36 | { |
37 | case EvqVaryingOut: |
38 | case EvqSmoothOut: |
39 | case EvqFlatOut: |
40 | case EvqCentroidOut: |
41 | case EvqVertexOut: |
42 | return true; |
43 | |
44 | default: break; |
45 | } |
46 | |
47 | return false; |
48 | } |
49 | |
50 | bool IsVaryingIn(TQualifier qualifier) |
51 | { |
52 | switch(qualifier) |
53 | { |
54 | case EvqVaryingIn: |
55 | case EvqSmoothIn: |
56 | case EvqFlatIn: |
57 | case EvqCentroidIn: |
58 | case EvqFragmentIn: |
59 | return true; |
60 | |
61 | default: break; |
62 | } |
63 | |
64 | return false; |
65 | } |
66 | |
67 | bool IsVarying(TQualifier qualifier) |
68 | { |
69 | return IsVaryingIn(qualifier) || IsVaryingOut(qualifier); |
70 | } |
71 | |
72 | bool IsAssignment(TOperator op) |
73 | { |
74 | switch(op) |
75 | { |
76 | case EOpPostIncrement: |
77 | case EOpPostDecrement: |
78 | case EOpPreIncrement: |
79 | case EOpPreDecrement: |
80 | case EOpAssign: |
81 | case EOpAddAssign: |
82 | case EOpSubAssign: |
83 | case EOpMulAssign: |
84 | case EOpVectorTimesMatrixAssign: |
85 | case EOpVectorTimesScalarAssign: |
86 | case EOpMatrixTimesScalarAssign: |
87 | case EOpMatrixTimesMatrixAssign: |
88 | case EOpDivAssign: |
89 | case EOpIModAssign: |
90 | case EOpBitShiftLeftAssign: |
91 | case EOpBitShiftRightAssign: |
92 | case EOpBitwiseAndAssign: |
93 | case EOpBitwiseXorAssign: |
94 | case EOpBitwiseOrAssign: |
95 | return true; |
96 | default: |
97 | return false; |
98 | } |
99 | } |
100 | } |
101 | |
102 | // |
103 | // Look at a '.' field selector string and change it into offsets |
104 | // for a vector. |
105 | // |
106 | bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc &line) |
107 | { |
108 | fields.num = (int) compString.size(); |
109 | if (fields.num > 4) { |
110 | error(line, "illegal vector field selection" , compString.c_str()); |
111 | return false; |
112 | } |
113 | |
114 | enum { |
115 | exyzw, |
116 | ergba, |
117 | estpq |
118 | } fieldSet[4]; |
119 | |
120 | for (int i = 0; i < fields.num; ++i) { |
121 | switch (compString[i]) { |
122 | case 'x': |
123 | fields.offsets[i] = 0; |
124 | fieldSet[i] = exyzw; |
125 | break; |
126 | case 'r': |
127 | fields.offsets[i] = 0; |
128 | fieldSet[i] = ergba; |
129 | break; |
130 | case 's': |
131 | fields.offsets[i] = 0; |
132 | fieldSet[i] = estpq; |
133 | break; |
134 | case 'y': |
135 | fields.offsets[i] = 1; |
136 | fieldSet[i] = exyzw; |
137 | break; |
138 | case 'g': |
139 | fields.offsets[i] = 1; |
140 | fieldSet[i] = ergba; |
141 | break; |
142 | case 't': |
143 | fields.offsets[i] = 1; |
144 | fieldSet[i] = estpq; |
145 | break; |
146 | case 'z': |
147 | fields.offsets[i] = 2; |
148 | fieldSet[i] = exyzw; |
149 | break; |
150 | case 'b': |
151 | fields.offsets[i] = 2; |
152 | fieldSet[i] = ergba; |
153 | break; |
154 | case 'p': |
155 | fields.offsets[i] = 2; |
156 | fieldSet[i] = estpq; |
157 | break; |
158 | case 'w': |
159 | fields.offsets[i] = 3; |
160 | fieldSet[i] = exyzw; |
161 | break; |
162 | case 'a': |
163 | fields.offsets[i] = 3; |
164 | fieldSet[i] = ergba; |
165 | break; |
166 | case 'q': |
167 | fields.offsets[i] = 3; |
168 | fieldSet[i] = estpq; |
169 | break; |
170 | default: |
171 | error(line, "illegal vector field selection" , compString.c_str()); |
172 | return false; |
173 | } |
174 | } |
175 | |
176 | for (int i = 0; i < fields.num; ++i) { |
177 | if (fields.offsets[i] >= vecSize) { |
178 | error(line, "vector field selection out of range" , compString.c_str()); |
179 | return false; |
180 | } |
181 | |
182 | if (i > 0) { |
183 | if (fieldSet[i] != fieldSet[i-1]) { |
184 | error(line, "illegal - vector component fields not from the same set" , compString.c_str()); |
185 | return false; |
186 | } |
187 | } |
188 | } |
189 | |
190 | return true; |
191 | } |
192 | |
193 | /////////////////////////////////////////////////////////////////////// |
194 | // |
195 | // Errors |
196 | // |
197 | //////////////////////////////////////////////////////////////////////// |
198 | |
199 | // |
200 | // Track whether errors have occurred. |
201 | // |
202 | void TParseContext::recover() |
203 | { |
204 | } |
205 | |
206 | // |
207 | // Used by flex/bison to output all syntax and parsing errors. |
208 | // |
209 | void TParseContext::error(const TSourceLoc& loc, |
210 | const char* reason, const char* token, |
211 | const char* ) |
212 | { |
213 | pp::SourceLocation srcLoc(loc.first_file, loc.first_line); |
214 | mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, |
215 | srcLoc, reason, token, extraInfo); |
216 | |
217 | } |
218 | |
219 | void TParseContext::warning(const TSourceLoc& loc, |
220 | const char* reason, const char* token, |
221 | const char* ) { |
222 | pp::SourceLocation srcLoc(loc.first_file, loc.first_line); |
223 | mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, |
224 | srcLoc, reason, token, extraInfo); |
225 | } |
226 | |
227 | void TParseContext::info(const TSourceLoc& loc, |
228 | const char* reason, const char* token, |
229 | const char* ) { |
230 | pp::SourceLocation srcLoc(loc.first_file, loc.first_line); |
231 | mDiagnostics.writeInfo(pp::Diagnostics::PP_INFO, |
232 | srcLoc, reason, token, extraInfo); |
233 | } |
234 | |
235 | void TParseContext::trace(const char* str) |
236 | { |
237 | mDiagnostics.writeDebug(str); |
238 | } |
239 | |
240 | // |
241 | // Same error message for all places assignments don't work. |
242 | // |
243 | void TParseContext::assignError(const TSourceLoc &line, const char* op, TString left, TString right) |
244 | { |
245 | std::stringstream ; |
246 | extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'" ; |
247 | std::string = extraInfoStream.str(); |
248 | error(line, "" , op, extraInfo.c_str()); |
249 | } |
250 | |
251 | // |
252 | // Same error message for all places unary operations don't work. |
253 | // |
254 | void TParseContext::unaryOpError(const TSourceLoc &line, const char* op, TString operand) |
255 | { |
256 | std::stringstream ; |
257 | extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand |
258 | << " (or there is no acceptable conversion)" ; |
259 | std::string = extraInfoStream.str(); |
260 | error(line, " wrong operand type" , op, extraInfo.c_str()); |
261 | } |
262 | |
263 | // |
264 | // Same error message for all binary operations don't work. |
265 | // |
266 | void TParseContext::binaryOpError(const TSourceLoc &line, const char* op, TString left, TString right) |
267 | { |
268 | std::stringstream ; |
269 | extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left |
270 | << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)" ; |
271 | std::string = extraInfoStream.str(); |
272 | error(line, " wrong operand types " , op, extraInfo.c_str()); |
273 | } |
274 | |
275 | bool TParseContext::precisionErrorCheck(const TSourceLoc &line, TPrecision precision, TBasicType type){ |
276 | if (!mChecksPrecisionErrors) |
277 | return false; |
278 | switch( type ){ |
279 | case EbtFloat: |
280 | if( precision == EbpUndefined ){ |
281 | error( line, "No precision specified for (float)" , "" ); |
282 | return true; |
283 | } |
284 | break; |
285 | case EbtInt: |
286 | if( precision == EbpUndefined ){ |
287 | error( line, "No precision specified (int)" , "" ); |
288 | return true; |
289 | } |
290 | break; |
291 | default: |
292 | return false; |
293 | } |
294 | return false; |
295 | } |
296 | |
297 | // |
298 | // Both test and if necessary, spit out an error, to see if the node is really |
299 | // an l-value that can be operated on this way. |
300 | // |
301 | // Returns true if the was an error. |
302 | // |
303 | bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char* op, TIntermTyped* node) |
304 | { |
305 | TIntermSymbol* symNode = node->getAsSymbolNode(); |
306 | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
307 | |
308 | if (binaryNode) { |
309 | bool errorReturn; |
310 | |
311 | switch(binaryNode->getOp()) { |
312 | case EOpIndexDirect: |
313 | case EOpIndexIndirect: |
314 | case EOpIndexDirectStruct: |
315 | return lValueErrorCheck(line, op, binaryNode->getLeft()); |
316 | case EOpVectorSwizzle: |
317 | errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); |
318 | if (!errorReturn) { |
319 | int offset[4] = {0,0,0,0}; |
320 | |
321 | TIntermTyped* rightNode = binaryNode->getRight(); |
322 | TIntermAggregate *aggrNode = rightNode->getAsAggregate(); |
323 | |
324 | for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); |
325 | p != aggrNode->getSequence().end(); p++) { |
326 | int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0); |
327 | offset[value]++; |
328 | if (offset[value] > 1) { |
329 | error(line, " l-value of swizzle cannot have duplicate components" , op); |
330 | |
331 | return true; |
332 | } |
333 | } |
334 | } |
335 | |
336 | return errorReturn; |
337 | case EOpIndexDirectInterfaceBlock: |
338 | default: |
339 | break; |
340 | } |
341 | error(line, " l-value required" , op); |
342 | |
343 | return true; |
344 | } |
345 | |
346 | |
347 | const char* symbol = 0; |
348 | if (symNode != 0) |
349 | symbol = symNode->getSymbol().c_str(); |
350 | |
351 | const char* message = 0; |
352 | switch (node->getQualifier()) { |
353 | case EvqConstExpr: message = "can't modify a const" ; break; |
354 | case EvqConstReadOnly: message = "can't modify a const" ; break; |
355 | case EvqAttribute: message = "can't modify an attribute" ; break; |
356 | case EvqFragmentIn: message = "can't modify an input" ; break; |
357 | case EvqVertexIn: message = "can't modify an input" ; break; |
358 | case EvqUniform: message = "can't modify a uniform" ; break; |
359 | case EvqSmoothIn: |
360 | case EvqFlatIn: |
361 | case EvqCentroidIn: |
362 | case EvqVaryingIn: message = "can't modify a varying" ; break; |
363 | case EvqInput: message = "can't modify an input" ; break; |
364 | case EvqFragCoord: message = "can't modify gl_FragCoord" ; break; |
365 | case EvqFrontFacing: message = "can't modify gl_FrontFacing" ; break; |
366 | case EvqPointCoord: message = "can't modify gl_PointCoord" ; break; |
367 | case EvqInstanceID: message = "can't modify gl_InstanceID" ; break; |
368 | case EvqVertexID: message = "can't modify gl_VertexID" ; break; |
369 | default: |
370 | |
371 | // |
372 | // Type that can't be written to? |
373 | // |
374 | if(IsSampler(node->getBasicType())) |
375 | { |
376 | message = "can't modify a sampler" ; |
377 | } |
378 | else if(node->getBasicType() == EbtVoid) |
379 | { |
380 | message = "can't modify void" ; |
381 | } |
382 | } |
383 | |
384 | if (message == 0 && binaryNode == 0 && symNode == 0) { |
385 | error(line, " l-value required" , op); |
386 | |
387 | return true; |
388 | } |
389 | |
390 | |
391 | // |
392 | // Everything else is okay, no error. |
393 | // |
394 | if (message == 0) |
395 | return false; |
396 | |
397 | // |
398 | // If we get here, we have an error and a message. |
399 | // |
400 | if (symNode) { |
401 | std::stringstream ; |
402 | extraInfoStream << "\"" << symbol << "\" (" << message << ")" ; |
403 | std::string = extraInfoStream.str(); |
404 | error(line, " l-value required" , op, extraInfo.c_str()); |
405 | } |
406 | else { |
407 | std::stringstream ; |
408 | extraInfoStream << "(" << message << ")" ; |
409 | std::string = extraInfoStream.str(); |
410 | error(line, " l-value required" , op, extraInfo.c_str()); |
411 | } |
412 | |
413 | return true; |
414 | } |
415 | |
416 | // |
417 | // Both test, and if necessary spit out an error, to see if the node is really |
418 | // a constant. |
419 | // |
420 | // Returns true if the was an error. |
421 | // |
422 | bool TParseContext::constErrorCheck(TIntermTyped* node) |
423 | { |
424 | if (node->getQualifier() == EvqConstExpr) |
425 | return false; |
426 | |
427 | error(node->getLine(), "constant expression required" , "" ); |
428 | |
429 | return true; |
430 | } |
431 | |
432 | // |
433 | // Both test, and if necessary spit out an error, to see if the node is really |
434 | // an integer. |
435 | // |
436 | // Returns true if the was an error. |
437 | // |
438 | bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) |
439 | { |
440 | if (node->isScalarInt()) |
441 | return false; |
442 | |
443 | error(node->getLine(), "integer expression required" , token); |
444 | |
445 | return true; |
446 | } |
447 | |
448 | // |
449 | // Both test, and if necessary spit out an error, to see if we are currently |
450 | // globally scoped. |
451 | // |
452 | // Returns true if the was an error. |
453 | // |
454 | bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char* token) |
455 | { |
456 | if (global) |
457 | return false; |
458 | |
459 | error(line, "only allowed at global scope" , token); |
460 | |
461 | return true; |
462 | } |
463 | |
464 | // |
465 | // For now, keep it simple: if it starts "gl_", it's reserved, independent |
466 | // of scope. Except, if the symbol table is at the built-in push-level, |
467 | // which is when we are parsing built-ins. |
468 | // Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a |
469 | // webgl shader. |
470 | // |
471 | // Returns true if there was an error. |
472 | // |
473 | bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString& identifier) |
474 | { |
475 | static const char* reservedErrMsg = "reserved built-in name" ; |
476 | if (!symbolTable.atBuiltInLevel()) { |
477 | if (identifier.compare(0, 3, "gl_" ) == 0) { |
478 | error(line, reservedErrMsg, "gl_" ); |
479 | return true; |
480 | } |
481 | if (identifier.find("__" ) != TString::npos) { |
482 | error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords" , identifier.c_str()); |
483 | return true; |
484 | } |
485 | } |
486 | |
487 | return false; |
488 | } |
489 | |
490 | // |
491 | // Make sure there is enough data provided to the constructor to build |
492 | // something of the type of the constructor. Also returns the type of |
493 | // the constructor. |
494 | // |
495 | // Returns true if there was an error in construction. |
496 | // |
497 | bool TParseContext::constructorErrorCheck(const TSourceLoc &line, TIntermNode* node, TFunction& function, TOperator op, TType* type) |
498 | { |
499 | *type = function.getReturnType(); |
500 | |
501 | bool constructingMatrix = false; |
502 | switch(op) { |
503 | case EOpConstructMat2: |
504 | case EOpConstructMat2x3: |
505 | case EOpConstructMat2x4: |
506 | case EOpConstructMat3x2: |
507 | case EOpConstructMat3: |
508 | case EOpConstructMat3x4: |
509 | case EOpConstructMat4x2: |
510 | case EOpConstructMat4x3: |
511 | case EOpConstructMat4: |
512 | constructingMatrix = true; |
513 | break; |
514 | default: |
515 | break; |
516 | } |
517 | |
518 | // |
519 | // Note: It's okay to have too many components available, but not okay to have unused |
520 | // arguments. 'full' will go to true when enough args have been seen. If we loop |
521 | // again, there is an extra argument, so 'overfull' will become true. |
522 | // |
523 | |
524 | size_t size = 0; |
525 | bool full = false; |
526 | bool overFull = false; |
527 | bool matrixInMatrix = false; |
528 | bool arrayArg = false; |
529 | for (size_t i = 0; i < function.getParamCount(); ++i) { |
530 | const TParameter& param = function.getParam(i); |
531 | size += param.type->getObjectSize(); |
532 | |
533 | if (constructingMatrix && param.type->isMatrix()) |
534 | matrixInMatrix = true; |
535 | if (full) |
536 | overFull = true; |
537 | if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) |
538 | full = true; |
539 | if (param.type->isArray()) |
540 | arrayArg = true; |
541 | } |
542 | |
543 | if(type->isArray()) { |
544 | if(type->getArraySize() == 0) { |
545 | type->setArraySize(function.getParamCount()); |
546 | } else if(type->getArraySize() != (int)function.getParamCount()) { |
547 | error(line, "array constructor needs one argument per array element" , "constructor" ); |
548 | return true; |
549 | } |
550 | } |
551 | |
552 | if (arrayArg && op != EOpConstructStruct) { |
553 | error(line, "constructing from a non-dereferenced array" , "constructor" ); |
554 | return true; |
555 | } |
556 | |
557 | if (matrixInMatrix && !type->isArray()) { |
558 | if (function.getParamCount() != 1) { |
559 | error(line, "constructing matrix from matrix can only take one argument" , "constructor" ); |
560 | return true; |
561 | } |
562 | } |
563 | |
564 | if (overFull) { |
565 | error(line, "too many arguments" , "constructor" ); |
566 | return true; |
567 | } |
568 | |
569 | if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) { |
570 | error(line, "Number of constructor parameters does not match the number of structure fields" , "constructor" ); |
571 | return true; |
572 | } |
573 | |
574 | if (!type->isMatrix() || !matrixInMatrix) { |
575 | if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || |
576 | (op == EOpConstructStruct && size < type->getObjectSize())) { |
577 | error(line, "not enough data provided for construction" , "constructor" ); |
578 | return true; |
579 | } |
580 | } |
581 | |
582 | TIntermTyped *typed = node ? node->getAsTyped() : 0; |
583 | if (typed == 0) { |
584 | error(line, "constructor argument does not have a type" , "constructor" ); |
585 | return true; |
586 | } |
587 | if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { |
588 | error(line, "cannot convert a sampler" , "constructor" ); |
589 | return true; |
590 | } |
591 | if (typed->getBasicType() == EbtVoid) { |
592 | error(line, "cannot convert a void" , "constructor" ); |
593 | return true; |
594 | } |
595 | |
596 | return false; |
597 | } |
598 | |
599 | // This function checks to see if a void variable has been declared and raise an error message for such a case |
600 | // |
601 | // returns true in case of an error |
602 | // |
603 | bool TParseContext::voidErrorCheck(const TSourceLoc &line, const TString& identifier, const TBasicType& type) |
604 | { |
605 | if(type == EbtVoid) { |
606 | error(line, "illegal use of type 'void'" , identifier.c_str()); |
607 | return true; |
608 | } |
609 | |
610 | return false; |
611 | } |
612 | |
613 | // This function checks to see if the node (for the expression) contains a scalar boolean expression or not |
614 | // |
615 | // returns true in case of an error |
616 | // |
617 | bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TIntermTyped* type) |
618 | { |
619 | if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { |
620 | error(line, "boolean expression expected" , "" ); |
621 | return true; |
622 | } |
623 | |
624 | return false; |
625 | } |
626 | |
627 | // This function checks to see if the node (for the expression) contains a scalar boolean expression or not |
628 | // |
629 | // returns true in case of an error |
630 | // |
631 | bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TPublicType& pType) |
632 | { |
633 | if (pType.type != EbtBool || pType.array || (pType.primarySize > 1) || (pType.secondarySize > 1)) { |
634 | error(line, "boolean expression expected" , "" ); |
635 | return true; |
636 | } |
637 | |
638 | return false; |
639 | } |
640 | |
641 | bool TParseContext::samplerErrorCheck(const TSourceLoc &line, const TPublicType& pType, const char* reason) |
642 | { |
643 | if (pType.type == EbtStruct) { |
644 | if (containsSampler(*pType.userDef)) { |
645 | error(line, reason, getBasicString(pType.type), "(structure contains a sampler)" ); |
646 | |
647 | return true; |
648 | } |
649 | |
650 | return false; |
651 | } else if (IsSampler(pType.type)) { |
652 | error(line, reason, getBasicString(pType.type)); |
653 | |
654 | return true; |
655 | } |
656 | |
657 | return false; |
658 | } |
659 | |
660 | bool TParseContext::structQualifierErrorCheck(const TSourceLoc &line, const TPublicType& pType) |
661 | { |
662 | switch(pType.qualifier) |
663 | { |
664 | case EvqVaryingOut: |
665 | case EvqSmooth: |
666 | case EvqFlat: |
667 | case EvqCentroidOut: |
668 | case EvqVaryingIn: |
669 | case EvqSmoothIn: |
670 | case EvqFlatIn: |
671 | case EvqCentroidIn: |
672 | case EvqAttribute: |
673 | case EvqVertexIn: |
674 | case EvqFragmentOut: |
675 | if(pType.type == EbtStruct) |
676 | { |
677 | error(line, "cannot be used with a structure" , getQualifierString(pType.qualifier)); |
678 | |
679 | return true; |
680 | } |
681 | break; |
682 | default: |
683 | break; |
684 | } |
685 | |
686 | if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform" )) |
687 | return true; |
688 | |
689 | // check for layout qualifier issues |
690 | if (pType.qualifier != EvqVertexIn && pType.qualifier != EvqFragmentOut && |
691 | layoutLocationErrorCheck(line, pType.layoutQualifier)) |
692 | { |
693 | return true; |
694 | } |
695 | |
696 | return false; |
697 | } |
698 | |
699 | // These checks are common for all declarations starting a declarator list, and declarators that follow an empty |
700 | // declaration. |
701 | // |
702 | bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation) |
703 | { |
704 | switch(publicType.qualifier) |
705 | { |
706 | case EvqVaryingIn: |
707 | case EvqVaryingOut: |
708 | case EvqAttribute: |
709 | case EvqVertexIn: |
710 | case EvqFragmentOut: |
711 | if(publicType.type == EbtStruct) |
712 | { |
713 | error(identifierLocation, "cannot be used with a structure" , |
714 | getQualifierString(publicType.qualifier)); |
715 | return true; |
716 | } |
717 | |
718 | default: break; |
719 | } |
720 | |
721 | if(publicType.qualifier != EvqUniform && samplerErrorCheck(identifierLocation, publicType, |
722 | "samplers must be uniform" )) |
723 | { |
724 | return true; |
725 | } |
726 | |
727 | // check for layout qualifier issues |
728 | const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; |
729 | |
730 | if(layoutQualifier.matrixPacking != EmpUnspecified) |
731 | { |
732 | error(identifierLocation, "layout qualifier" , getMatrixPackingString(layoutQualifier.matrixPacking), |
733 | "only valid for interface blocks" ); |
734 | return true; |
735 | } |
736 | |
737 | if(layoutQualifier.blockStorage != EbsUnspecified) |
738 | { |
739 | error(identifierLocation, "layout qualifier" , getBlockStorageString(layoutQualifier.blockStorage), |
740 | "only valid for interface blocks" ); |
741 | return true; |
742 | } |
743 | |
744 | if(publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && |
745 | layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier)) |
746 | { |
747 | return true; |
748 | } |
749 | |
750 | return false; |
751 | } |
752 | |
753 | bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier) |
754 | { |
755 | if(layoutQualifier.location != -1) |
756 | { |
757 | error(location, "invalid layout qualifier:" , "location" , "only valid on program inputs and outputs" ); |
758 | return true; |
759 | } |
760 | |
761 | return false; |
762 | } |
763 | |
764 | bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType) |
765 | { |
766 | if(pType.layoutQualifier.location != -1) |
767 | { |
768 | error(line, "location must only be specified for a single input or output variable" , "location" ); |
769 | return true; |
770 | } |
771 | |
772 | return false; |
773 | } |
774 | |
775 | bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line, TQualifier qualifier, const TType& type) |
776 | { |
777 | if ((qualifier == EvqOut || qualifier == EvqInOut) && |
778 | type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { |
779 | error(line, "samplers cannot be output parameters" , type.getBasicString()); |
780 | return true; |
781 | } |
782 | |
783 | return false; |
784 | } |
785 | |
786 | bool TParseContext::containsSampler(TType& type) |
787 | { |
788 | if (IsSampler(type.getBasicType())) |
789 | return true; |
790 | |
791 | if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { |
792 | for(const auto &field : type.getStruct()->fields()) { |
793 | if (containsSampler(*(field->type()))) |
794 | return true; |
795 | } |
796 | } |
797 | |
798 | return false; |
799 | } |
800 | |
801 | // |
802 | // Do size checking for an array type's size. |
803 | // |
804 | // Returns true if there was an error. |
805 | // |
806 | bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped* expr, int& size) |
807 | { |
808 | TIntermConstantUnion* constant = expr->getAsConstantUnion(); |
809 | |
810 | if (expr->getQualifier() != EvqConstExpr || constant == 0 || !constant->isScalarInt()) |
811 | { |
812 | error(line, "array size must be a constant integer expression" , "" ); |
813 | size = 1; |
814 | return true; |
815 | } |
816 | |
817 | if (constant->getBasicType() == EbtUInt) |
818 | { |
819 | unsigned int uintSize = constant->getUConst(0); |
820 | if (uintSize > static_cast<unsigned int>(std::numeric_limits<int>::max())) |
821 | { |
822 | error(line, "array size too large" , "" ); |
823 | size = 1; |
824 | return true; |
825 | } |
826 | |
827 | size = static_cast<int>(uintSize); |
828 | } |
829 | else |
830 | { |
831 | size = constant->getIConst(0); |
832 | |
833 | if (size < 0) |
834 | { |
835 | error(line, "array size must be non-negative" , "" ); |
836 | size = 1; |
837 | return true; |
838 | } |
839 | } |
840 | |
841 | if(size == 0) |
842 | { |
843 | error(line, "array size must be greater than zero" , "" ); |
844 | return true; |
845 | } |
846 | |
847 | return false; |
848 | } |
849 | |
850 | // |
851 | // See if this qualifier can be an array. |
852 | // |
853 | // Returns true if there is an error. |
854 | // |
855 | bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, TPublicType type) |
856 | { |
857 | if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConstExpr && mShaderVersion < 300)) { |
858 | error(line, "cannot declare arrays of this qualifier" , TType(type).getCompleteString().c_str()); |
859 | return true; |
860 | } |
861 | |
862 | return false; |
863 | } |
864 | |
865 | // |
866 | // See if this type can be an array. |
867 | // |
868 | // Returns true if there is an error. |
869 | // |
870 | bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, TPublicType type) |
871 | { |
872 | // |
873 | // Can the type be an array? |
874 | // |
875 | if (type.array) { |
876 | error(line, "cannot declare arrays of arrays" , TType(type).getCompleteString().c_str()); |
877 | return true; |
878 | } |
879 | |
880 | // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. |
881 | // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section 4.3.4). |
882 | if(mShaderVersion >= 300 && type.type == EbtStruct && IsVarying(type.qualifier)) |
883 | { |
884 | error(line, "cannot declare arrays of structs of this qualifier" , |
885 | TType(type).getCompleteString().c_str()); |
886 | return true; |
887 | } |
888 | |
889 | return false; |
890 | } |
891 | |
892 | bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, const TSourceLoc &line) |
893 | { |
894 | bool builtIn = false; |
895 | TSymbol* symbol = symbolTable.find(node->getSymbol(), mShaderVersion, &builtIn); |
896 | if (symbol == 0) { |
897 | error(line, " undeclared identifier" , node->getSymbol().c_str()); |
898 | return true; |
899 | } |
900 | TVariable* variable = static_cast<TVariable*>(symbol); |
901 | |
902 | type->setArrayInformationType(variable->getArrayInformationType()); |
903 | variable->updateArrayInformationType(type); |
904 | |
905 | // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers |
906 | // its an error |
907 | if (node->getSymbol() == "gl_FragData" ) { |
908 | TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers" , mShaderVersion, &builtIn); |
909 | ASSERT(fragData); |
910 | |
911 | int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst(); |
912 | if (fragDataValue <= size) { |
913 | error(line, "" , "[" , "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers" ); |
914 | return true; |
915 | } |
916 | } |
917 | |
918 | // we dont want to update the maxArraySize when this flag is not set, we just want to include this |
919 | // node type in the chain of node types so that its updated when a higher maxArraySize comes in. |
920 | if (!updateFlag) |
921 | return false; |
922 | |
923 | size++; |
924 | variable->getType().setMaxArraySize(size); |
925 | type->setMaxArraySize(size); |
926 | TType* tt = type; |
927 | |
928 | while(tt->getArrayInformationType() != 0) { |
929 | tt = tt->getArrayInformationType(); |
930 | tt->setMaxArraySize(size); |
931 | } |
932 | |
933 | return false; |
934 | } |
935 | |
936 | // |
937 | // Enforce non-initializer type/qualifier rules. |
938 | // |
939 | // Returns true if there was an error. |
940 | // |
941 | bool TParseContext::nonInitConstErrorCheck(const TSourceLoc &line, TString& identifier, TPublicType& type, bool array) |
942 | { |
943 | if (type.qualifier == EvqConstExpr) |
944 | { |
945 | // Make the qualifier make sense. |
946 | type.qualifier = EvqTemporary; |
947 | |
948 | if (array) |
949 | { |
950 | error(line, "arrays may not be declared constant since they cannot be initialized" , identifier.c_str()); |
951 | } |
952 | else if (type.isStructureContainingArrays()) |
953 | { |
954 | error(line, "structures containing arrays may not be declared constant since they cannot be initialized" , identifier.c_str()); |
955 | } |
956 | else |
957 | { |
958 | error(line, "variables with qualifier 'const' must be initialized" , identifier.c_str()); |
959 | } |
960 | |
961 | return true; |
962 | } |
963 | |
964 | return false; |
965 | } |
966 | |
967 | // |
968 | // Do semantic checking for a variable declaration that has no initializer, |
969 | // and update the symbol table. |
970 | // |
971 | // Returns true if there was an error. |
972 | // |
973 | bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, const TString& identifier, TPublicType& type) |
974 | { |
975 | if(type.qualifier == EvqConstExpr) |
976 | { |
977 | // Make the qualifier make sense. |
978 | type.qualifier = EvqTemporary; |
979 | |
980 | // Generate informative error messages for ESSL1. |
981 | // In ESSL3 arrays and structures containing arrays can be constant. |
982 | if(mShaderVersion < 300 && type.isStructureContainingArrays()) |
983 | { |
984 | error(line, |
985 | "structures containing arrays may not be declared constant since they cannot be initialized" , |
986 | identifier.c_str()); |
987 | } |
988 | else |
989 | { |
990 | error(line, "variables with qualifier 'const' must be initialized" , identifier.c_str()); |
991 | } |
992 | |
993 | return true; |
994 | } |
995 | if(type.isUnsizedArray()) |
996 | { |
997 | error(line, "implicitly sized arrays need to be initialized" , identifier.c_str()); |
998 | return true; |
999 | } |
1000 | return false; |
1001 | } |
1002 | |
1003 | // Do some simple checks that are shared between all variable declarations, |
1004 | // and update the symbol table. |
1005 | // |
1006 | // Returns true if declaring the variable succeeded. |
1007 | // |
1008 | bool TParseContext::declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, |
1009 | TVariable **variable) |
1010 | { |
1011 | ASSERT((*variable) == nullptr); |
1012 | |
1013 | // gl_LastFragData may be redeclared with a new precision qualifier |
1014 | if(type.isArray() && identifier.compare(0, 15, "gl_LastFragData" ) == 0) |
1015 | { |
1016 | const TVariable *maxDrawBuffers = |
1017 | static_cast<const TVariable *>(symbolTable.findBuiltIn("gl_MaxDrawBuffers" , mShaderVersion)); |
1018 | if(type.getArraySize() != maxDrawBuffers->getConstPointer()->getIConst()) |
1019 | { |
1020 | error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers" , identifier.c_str()); |
1021 | return false; |
1022 | } |
1023 | } |
1024 | |
1025 | if(reservedErrorCheck(line, identifier)) |
1026 | return false; |
1027 | |
1028 | (*variable) = new TVariable(&identifier, type); |
1029 | if(!symbolTable.declare(*variable)) |
1030 | { |
1031 | error(line, "redefinition" , identifier.c_str()); |
1032 | delete (*variable); |
1033 | (*variable) = nullptr; |
1034 | return false; |
1035 | } |
1036 | |
1037 | if(voidErrorCheck(line, identifier, type.getBasicType())) |
1038 | return false; |
1039 | |
1040 | return true; |
1041 | } |
1042 | |
1043 | bool TParseContext::paramErrorCheck(const TSourceLoc &line, TQualifier qualifier, TQualifier paramQualifier, TType* type) |
1044 | { |
1045 | if (qualifier != EvqConstReadOnly && qualifier != EvqTemporary) { |
1046 | error(line, "qualifier not allowed on function parameter" , getQualifierString(qualifier)); |
1047 | return true; |
1048 | } |
1049 | if (qualifier == EvqConstReadOnly && paramQualifier != EvqIn) { |
1050 | error(line, "qualifier not allowed with " , getQualifierString(qualifier), getQualifierString(paramQualifier)); |
1051 | return true; |
1052 | } |
1053 | |
1054 | if (qualifier == EvqConstReadOnly) |
1055 | type->setQualifier(EvqConstReadOnly); |
1056 | else |
1057 | type->setQualifier(paramQualifier); |
1058 | |
1059 | return false; |
1060 | } |
1061 | |
1062 | bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString& extension) |
1063 | { |
1064 | const TExtensionBehavior& extBehavior = extensionBehavior(); |
1065 | TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); |
1066 | if (iter == extBehavior.end()) { |
1067 | error(line, "extension" , extension.c_str(), "is not supported" ); |
1068 | return true; |
1069 | } |
1070 | // In GLSL ES, an extension's default behavior is "disable". |
1071 | if (iter->second == EBhDisable || iter->second == EBhUndefined) { |
1072 | error(line, "extension" , extension.c_str(), "is disabled" ); |
1073 | return true; |
1074 | } |
1075 | if (iter->second == EBhWarn) { |
1076 | warning(line, "extension" , extension.c_str(), "is being used" ); |
1077 | return false; |
1078 | } |
1079 | |
1080 | return false; |
1081 | } |
1082 | |
1083 | bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate) |
1084 | { |
1085 | for(size_t i = 0; i < fnCandidate->getParamCount(); ++i) |
1086 | { |
1087 | TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); |
1088 | if(qual == EvqOut || qual == EvqInOut) |
1089 | { |
1090 | TIntermTyped *node = (aggregate->getSequence())[i]->getAsTyped(); |
1091 | if(lValueErrorCheck(node->getLine(), "assign" , node)) |
1092 | { |
1093 | error(node->getLine(), |
1094 | "Constant value cannot be passed for 'out' or 'inout' parameters." , "Error" ); |
1095 | recover(); |
1096 | return true; |
1097 | } |
1098 | } |
1099 | } |
1100 | return false; |
1101 | } |
1102 | |
1103 | void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation) |
1104 | { |
1105 | switch(qualifier) |
1106 | { |
1107 | case EvqVaryingOut: |
1108 | case EvqSmoothOut: |
1109 | case EvqFlatOut: |
1110 | case EvqCentroidOut: |
1111 | case EvqVertexOut: |
1112 | case EvqFragmentOut: |
1113 | break; |
1114 | default: |
1115 | error(invariantLocation, "Only out variables can be invariant." , "invariant" ); |
1116 | recover(); |
1117 | break; |
1118 | } |
1119 | } |
1120 | |
1121 | bool TParseContext::supportsExtension(const char* extension) |
1122 | { |
1123 | const TExtensionBehavior& extbehavior = extensionBehavior(); |
1124 | TExtensionBehavior::const_iterator iter = extbehavior.find(extension); |
1125 | return (iter != extbehavior.end()); |
1126 | } |
1127 | |
1128 | void TParseContext::handleExtensionDirective(const TSourceLoc &line, const char* extName, const char* behavior) |
1129 | { |
1130 | pp::SourceLocation loc(line.first_file, line.first_line); |
1131 | mDirectiveHandler.handleExtension(loc, extName, behavior); |
1132 | } |
1133 | |
1134 | void TParseContext::handlePragmaDirective(const TSourceLoc &line, const char* name, const char* value, bool stdgl) |
1135 | { |
1136 | pp::SourceLocation loc(line.first_file, line.first_line); |
1137 | mDirectiveHandler.handlePragma(loc, name, value, stdgl); |
1138 | } |
1139 | |
1140 | ///////////////////////////////////////////////////////////////////////////////// |
1141 | // |
1142 | // Non-Errors. |
1143 | // |
1144 | ///////////////////////////////////////////////////////////////////////////////// |
1145 | |
1146 | const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, |
1147 | const TString *name, |
1148 | const TSymbol *symbol) |
1149 | { |
1150 | const TVariable *variable = nullptr; |
1151 | |
1152 | if(!symbol) |
1153 | { |
1154 | error(location, "undeclared identifier" , name->c_str()); |
1155 | recover(); |
1156 | } |
1157 | else if(!symbol->isVariable()) |
1158 | { |
1159 | error(location, "variable expected" , name->c_str()); |
1160 | recover(); |
1161 | } |
1162 | else |
1163 | { |
1164 | variable = static_cast<const TVariable*>(symbol); |
1165 | |
1166 | if(symbolTable.findBuiltIn(variable->getName(), mShaderVersion)) |
1167 | { |
1168 | recover(); |
1169 | } |
1170 | |
1171 | // Reject shaders using both gl_FragData and gl_FragColor |
1172 | TQualifier qualifier = variable->getType().getQualifier(); |
1173 | if(qualifier == EvqFragData) |
1174 | { |
1175 | mUsesFragData = true; |
1176 | } |
1177 | else if(qualifier == EvqFragColor) |
1178 | { |
1179 | mUsesFragColor = true; |
1180 | } |
1181 | |
1182 | // This validation is not quite correct - it's only an error to write to |
1183 | // both FragData and FragColor. For simplicity, and because users shouldn't |
1184 | // be rewarded for reading from undefined variables, return an error |
1185 | // if they are both referenced, rather than assigned. |
1186 | if(mUsesFragData && mUsesFragColor) |
1187 | { |
1188 | error(location, "cannot use both gl_FragData and gl_FragColor" , name->c_str()); |
1189 | recover(); |
1190 | } |
1191 | } |
1192 | |
1193 | if(!variable) |
1194 | { |
1195 | TType type(EbtFloat, EbpUndefined); |
1196 | TVariable *fakeVariable = new TVariable(name, type); |
1197 | symbolTable.declare(fakeVariable); |
1198 | variable = fakeVariable; |
1199 | } |
1200 | |
1201 | return variable; |
1202 | } |
1203 | |
1204 | // |
1205 | // Look up a function name in the symbol table, and make sure it is a function. |
1206 | // |
1207 | // Return the function symbol if found, otherwise 0. |
1208 | // |
1209 | const TFunction* TParseContext::findFunction(const TSourceLoc &line, TFunction* call, bool *builtIn) |
1210 | { |
1211 | // First find by unmangled name to check whether the function name has been |
1212 | // hidden by a variable name or struct typename. |
1213 | const TSymbol* symbol = symbolTable.find(call->getName(), mShaderVersion, builtIn); |
1214 | if (!symbol || symbol->isFunction()) { |
1215 | symbol = symbolTable.find(call->getMangledName(), mShaderVersion, builtIn); |
1216 | } |
1217 | |
1218 | if (!symbol) { |
1219 | error(line, "no matching overloaded function found" , call->getName().c_str()); |
1220 | return nullptr; |
1221 | } |
1222 | |
1223 | if (!symbol->isFunction()) { |
1224 | error(line, "function name expected" , call->getName().c_str()); |
1225 | return nullptr; |
1226 | } |
1227 | |
1228 | return static_cast<const TFunction*>(symbol); |
1229 | } |
1230 | |
1231 | // |
1232 | // Initializers show up in several places in the grammar. Have one set of |
1233 | // code to handle them here. |
1234 | // |
1235 | bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, const TPublicType& pType, |
1236 | TIntermTyped *initializer, TIntermNode **intermNode) |
1237 | { |
1238 | ASSERT(intermNode != nullptr); |
1239 | TType type = TType(pType); |
1240 | |
1241 | if(type.isUnsizedArray()) |
1242 | { |
1243 | // We have not checked yet whether the initializer actually is an array or not. |
1244 | if(initializer->isArray()) |
1245 | { |
1246 | type.setArraySize(initializer->getArraySize()); |
1247 | } |
1248 | else |
1249 | { |
1250 | // Having a non-array initializer for an unsized array will result in an error later, |
1251 | // so we don't generate an error message here. |
1252 | type.setArraySize(1u); |
1253 | } |
1254 | } |
1255 | |
1256 | TVariable *variable = nullptr; |
1257 | if(!declareVariable(line, identifier, type, &variable)) |
1258 | { |
1259 | return true; |
1260 | } |
1261 | |
1262 | if(symbolTable.atGlobalLevel() && initializer->getQualifier() != EvqConstExpr) |
1263 | { |
1264 | error(line, "global variable initializers must be constant expressions" , "=" ); |
1265 | return true; |
1266 | } |
1267 | |
1268 | // |
1269 | // identifier must be of type constant, a global, or a temporary |
1270 | // |
1271 | TQualifier qualifier = type.getQualifier(); |
1272 | if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConstExpr)) { |
1273 | error(line, " cannot initialize this type of qualifier " , variable->getType().getQualifierString()); |
1274 | return true; |
1275 | } |
1276 | // |
1277 | // test for and propagate constant |
1278 | // |
1279 | |
1280 | if (qualifier == EvqConstExpr) { |
1281 | if (qualifier != initializer->getQualifier()) { |
1282 | std::stringstream ; |
1283 | extraInfoStream << "'" << variable->getType().getCompleteString() << "'" ; |
1284 | std::string = extraInfoStream.str(); |
1285 | error(line, " assigning non-constant to" , "=" , extraInfo.c_str()); |
1286 | variable->getType().setQualifier(EvqTemporary); |
1287 | return true; |
1288 | } |
1289 | |
1290 | if (type != initializer->getType()) { |
1291 | error(line, " non-matching types for const initializer " , |
1292 | variable->getType().getQualifierString()); |
1293 | variable->getType().setQualifier(EvqTemporary); |
1294 | return true; |
1295 | } |
1296 | |
1297 | if (initializer->getAsConstantUnion()) { |
1298 | variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); |
1299 | } else if (initializer->getAsSymbolNode()) { |
1300 | const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0); |
1301 | const TVariable* tVar = static_cast<const TVariable*>(symbol); |
1302 | |
1303 | ConstantUnion* constArray = tVar->getConstPointer(); |
1304 | variable->shareConstPointer(constArray); |
1305 | } |
1306 | } |
1307 | |
1308 | // Constants which aren't indexable arrays get propagated by value |
1309 | // and thus don't need to initialize the symbol. |
1310 | if (variable->isConstant() && !(type.isArray() && type.getArraySize() > 1)) |
1311 | { |
1312 | *intermNode = nullptr; |
1313 | } |
1314 | else |
1315 | { |
1316 | TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); |
1317 | *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line); |
1318 | if(*intermNode == nullptr) { |
1319 | assignError(line, "=" , intermSymbol->getCompleteString(), initializer->getCompleteString()); |
1320 | return true; |
1321 | } |
1322 | } |
1323 | |
1324 | return false; |
1325 | } |
1326 | |
1327 | TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier) |
1328 | { |
1329 | TPublicType returnType = typeSpecifier; |
1330 | returnType.qualifier = qualifier; |
1331 | returnType.invariant = invariant; |
1332 | returnType.layoutQualifier = layoutQualifier; |
1333 | |
1334 | if(mShaderVersion < 300) |
1335 | { |
1336 | if(typeSpecifier.array) |
1337 | { |
1338 | error(typeSpecifier.line, "not supported" , "first-class array" ); |
1339 | returnType.clearArrayness(); |
1340 | } |
1341 | |
1342 | if(qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) |
1343 | { |
1344 | error(typeSpecifier.line, "cannot be bool or int" , getQualifierString(qualifier)); |
1345 | recover(); |
1346 | } |
1347 | |
1348 | if((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) && |
1349 | (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) |
1350 | { |
1351 | error(typeSpecifier.line, "cannot be bool or int" , getQualifierString(qualifier)); |
1352 | recover(); |
1353 | } |
1354 | } |
1355 | else |
1356 | { |
1357 | if(!returnType.layoutQualifier.isEmpty()) |
1358 | { |
1359 | globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout" ); |
1360 | } |
1361 | |
1362 | if(IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || returnType.qualifier == EvqFragmentOut) |
1363 | { |
1364 | checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, typeSpecifier.line); |
1365 | } |
1366 | } |
1367 | |
1368 | return returnType; |
1369 | } |
1370 | |
1371 | void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, |
1372 | const TPublicType &type, |
1373 | const TSourceLoc &qualifierLocation) |
1374 | { |
1375 | // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. |
1376 | if(type.type == EbtBool) |
1377 | { |
1378 | error(qualifierLocation, "cannot be bool" , getQualifierString(qualifier)); |
1379 | } |
1380 | |
1381 | // Specific restrictions apply for vertex shader inputs and fragment shader outputs. |
1382 | switch(qualifier) |
1383 | { |
1384 | case EvqVertexIn: |
1385 | // ESSL 3.00 section 4.3.4 |
1386 | if(type.array) |
1387 | { |
1388 | error(qualifierLocation, "cannot be array" , getQualifierString(qualifier)); |
1389 | } |
1390 | // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck |
1391 | return; |
1392 | case EvqFragmentOut: |
1393 | // ESSL 3.00 section 4.3.6 |
1394 | if(type.isMatrix()) |
1395 | { |
1396 | error(qualifierLocation, "cannot be matrix" , getQualifierString(qualifier)); |
1397 | } |
1398 | // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck |
1399 | return; |
1400 | default: |
1401 | break; |
1402 | } |
1403 | |
1404 | // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of |
1405 | // restrictions. |
1406 | bool typeContainsIntegers = (type.type == EbtInt || type.type == EbtUInt || |
1407 | type.isStructureContainingType(EbtInt) || |
1408 | type.isStructureContainingType(EbtUInt)); |
1409 | if(typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) |
1410 | { |
1411 | error(qualifierLocation, "must use 'flat' interpolation here" , getQualifierString(qualifier)); |
1412 | } |
1413 | |
1414 | if(type.type == EbtStruct) |
1415 | { |
1416 | // ESSL 3.00 sections 4.3.4 and 4.3.6. |
1417 | // These restrictions are only implied by the ESSL 3.00 spec, but |
1418 | // the ESSL 3.10 spec lists these restrictions explicitly. |
1419 | if(type.array) |
1420 | { |
1421 | error(qualifierLocation, "cannot be an array of structures" , getQualifierString(qualifier)); |
1422 | } |
1423 | if(type.isStructureContainingArrays()) |
1424 | { |
1425 | error(qualifierLocation, "cannot be a structure containing an array" , getQualifierString(qualifier)); |
1426 | } |
1427 | if(type.isStructureContainingType(EbtStruct)) |
1428 | { |
1429 | error(qualifierLocation, "cannot be a structure containing a structure" , getQualifierString(qualifier)); |
1430 | } |
1431 | if(type.isStructureContainingType(EbtBool)) |
1432 | { |
1433 | error(qualifierLocation, "cannot be a structure containing a bool" , getQualifierString(qualifier)); |
1434 | } |
1435 | } |
1436 | } |
1437 | |
1438 | TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType, |
1439 | const TSourceLoc &identifierOrTypeLocation, |
1440 | const TString &identifier) |
1441 | { |
1442 | TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation); |
1443 | |
1444 | bool emptyDeclaration = (identifier == "" ); |
1445 | |
1446 | mDeferredSingleDeclarationErrorCheck = emptyDeclaration; |
1447 | |
1448 | if(emptyDeclaration) |
1449 | { |
1450 | if(publicType.isUnsizedArray()) |
1451 | { |
1452 | // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an error. |
1453 | // It is assumed that this applies to empty declarations as well. |
1454 | error(identifierOrTypeLocation, "empty array declaration needs to specify a size" , identifier.c_str()); |
1455 | } |
1456 | } |
1457 | else |
1458 | { |
1459 | if(singleDeclarationErrorCheck(publicType, identifierOrTypeLocation)) |
1460 | recover(); |
1461 | |
1462 | if(nonInitErrorCheck(identifierOrTypeLocation, identifier, publicType)) |
1463 | recover(); |
1464 | |
1465 | TVariable *variable = nullptr; |
1466 | if(!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable)) |
1467 | recover(); |
1468 | |
1469 | if(variable && symbol) |
1470 | symbol->setId(variable->getUniqueId()); |
1471 | } |
1472 | |
1473 | return intermediate.makeAggregate(symbol, identifierOrTypeLocation); |
1474 | } |
1475 | |
1476 | TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, |
1477 | const TSourceLoc &identifierLocation, |
1478 | const TString &identifier, |
1479 | const TSourceLoc &indexLocation, |
1480 | TIntermTyped *indexExpression) |
1481 | { |
1482 | mDeferredSingleDeclarationErrorCheck = false; |
1483 | |
1484 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1485 | recover(); |
1486 | |
1487 | if(nonInitErrorCheck(identifierLocation, identifier, publicType)) |
1488 | recover(); |
1489 | |
1490 | if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType)) |
1491 | { |
1492 | recover(); |
1493 | } |
1494 | |
1495 | TType arrayType(publicType); |
1496 | |
1497 | int size = 0; |
1498 | if(arraySizeErrorCheck(identifierLocation, indexExpression, size)) |
1499 | { |
1500 | recover(); |
1501 | } |
1502 | // Make the type an array even if size check failed. |
1503 | // This ensures useless error messages regarding the variable's non-arrayness won't follow. |
1504 | arrayType.setArraySize(size); |
1505 | |
1506 | TVariable *variable = nullptr; |
1507 | if(!declareVariable(identifierLocation, identifier, arrayType, &variable)) |
1508 | recover(); |
1509 | |
1510 | TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation); |
1511 | if(variable && symbol) |
1512 | symbol->setId(variable->getUniqueId()); |
1513 | |
1514 | return intermediate.makeAggregate(symbol, identifierLocation); |
1515 | } |
1516 | |
1517 | TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, |
1518 | const TSourceLoc &identifierLocation, |
1519 | const TString &identifier, |
1520 | const TSourceLoc &initLocation, |
1521 | TIntermTyped *initializer) |
1522 | { |
1523 | mDeferredSingleDeclarationErrorCheck = false; |
1524 | |
1525 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1526 | recover(); |
1527 | |
1528 | TIntermNode *intermNode = nullptr; |
1529 | if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) |
1530 | { |
1531 | // |
1532 | // Build intermediate representation |
1533 | // |
1534 | return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr; |
1535 | } |
1536 | else |
1537 | { |
1538 | recover(); |
1539 | return nullptr; |
1540 | } |
1541 | } |
1542 | |
1543 | TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(TPublicType &publicType, |
1544 | const TSourceLoc &identifierLocation, |
1545 | const TString &identifier, |
1546 | const TSourceLoc &indexLocation, |
1547 | TIntermTyped *indexExpression, |
1548 | const TSourceLoc &initLocation, |
1549 | TIntermTyped *initializer) |
1550 | { |
1551 | mDeferredSingleDeclarationErrorCheck = false; |
1552 | |
1553 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1554 | recover(); |
1555 | |
1556 | if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType)) |
1557 | { |
1558 | recover(); |
1559 | } |
1560 | |
1561 | TPublicType arrayType(publicType); |
1562 | |
1563 | int size = 0; |
1564 | // If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer. |
1565 | if(indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size)) |
1566 | { |
1567 | recover(); |
1568 | } |
1569 | // Make the type an array even if size check failed. |
1570 | // This ensures useless error messages regarding the variable's non-arrayness won't follow. |
1571 | arrayType.setArray(true, size); |
1572 | |
1573 | // initNode will correspond to the whole of "type b[n] = initializer". |
1574 | TIntermNode *initNode = nullptr; |
1575 | if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) |
1576 | { |
1577 | return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr; |
1578 | } |
1579 | else |
1580 | { |
1581 | recover(); |
1582 | return nullptr; |
1583 | } |
1584 | } |
1585 | |
1586 | TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc, |
1587 | const TSourceLoc &identifierLoc, |
1588 | const TString *identifier, |
1589 | const TSymbol *symbol) |
1590 | { |
1591 | // invariant declaration |
1592 | if(globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying" )) |
1593 | { |
1594 | recover(); |
1595 | } |
1596 | |
1597 | if(!symbol) |
1598 | { |
1599 | error(identifierLoc, "undeclared identifier declared as invariant" , identifier->c_str()); |
1600 | recover(); |
1601 | return nullptr; |
1602 | } |
1603 | else |
1604 | { |
1605 | const TString kGlFrontFacing("gl_FrontFacing" ); |
1606 | if(*identifier == kGlFrontFacing) |
1607 | { |
1608 | error(identifierLoc, "identifier should not be declared as invariant" , identifier->c_str()); |
1609 | recover(); |
1610 | return nullptr; |
1611 | } |
1612 | symbolTable.addInvariantVarying(std::string(identifier->c_str())); |
1613 | const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); |
1614 | ASSERT(variable); |
1615 | const TType &type = variable->getType(); |
1616 | TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(), |
1617 | *identifier, type, identifierLoc); |
1618 | |
1619 | TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc); |
1620 | aggregate->setOp(EOpInvariantDeclaration); |
1621 | return aggregate; |
1622 | } |
1623 | } |
1624 | |
1625 | TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, |
1626 | const TSourceLoc &identifierLocation, const TString &identifier) |
1627 | { |
1628 | // If the declaration starting this declarator list was empty (example: int,), some checks were not performed. |
1629 | if(mDeferredSingleDeclarationErrorCheck) |
1630 | { |
1631 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1632 | recover(); |
1633 | mDeferredSingleDeclarationErrorCheck = false; |
1634 | } |
1635 | |
1636 | if(locationDeclaratorListCheck(identifierLocation, publicType)) |
1637 | recover(); |
1638 | |
1639 | if(nonInitErrorCheck(identifierLocation, identifier, publicType)) |
1640 | recover(); |
1641 | |
1642 | TVariable *variable = nullptr; |
1643 | if(!declareVariable(identifierLocation, identifier, TType(publicType), &variable)) |
1644 | recover(); |
1645 | |
1646 | TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); |
1647 | if(variable && symbol) |
1648 | symbol->setId(variable->getUniqueId()); |
1649 | |
1650 | return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); |
1651 | } |
1652 | |
1653 | TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, |
1654 | const TSourceLoc &identifierLocation, const TString &identifier, |
1655 | const TSourceLoc &arrayLocation, TIntermTyped *indexExpression) |
1656 | { |
1657 | // If the declaration starting this declarator list was empty (example: int,), some checks were not performed. |
1658 | if(mDeferredSingleDeclarationErrorCheck) |
1659 | { |
1660 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1661 | recover(); |
1662 | mDeferredSingleDeclarationErrorCheck = false; |
1663 | } |
1664 | |
1665 | if(locationDeclaratorListCheck(identifierLocation, publicType)) |
1666 | recover(); |
1667 | |
1668 | if(nonInitErrorCheck(identifierLocation, identifier, publicType)) |
1669 | recover(); |
1670 | |
1671 | if(arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType)) |
1672 | { |
1673 | recover(); |
1674 | } |
1675 | else |
1676 | { |
1677 | TType arrayType = TType(publicType); |
1678 | int size = 0; |
1679 | if(arraySizeErrorCheck(arrayLocation, indexExpression, size)) |
1680 | { |
1681 | recover(); |
1682 | } |
1683 | arrayType.setArraySize(size); |
1684 | |
1685 | TVariable *variable = nullptr; |
1686 | if(!declareVariable(identifierLocation, identifier, arrayType, &variable)) |
1687 | recover(); |
1688 | |
1689 | TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation); |
1690 | if(variable && symbol) |
1691 | symbol->setId(variable->getUniqueId()); |
1692 | |
1693 | return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); |
1694 | } |
1695 | |
1696 | return nullptr; |
1697 | } |
1698 | |
1699 | TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType, TIntermAggregate *aggregateDeclaration, |
1700 | const TSourceLoc &identifierLocation, const TString &identifier, |
1701 | const TSourceLoc &initLocation, TIntermTyped *initializer) |
1702 | { |
1703 | // If the declaration starting this declarator list was empty (example: int,), some checks were not performed. |
1704 | if(mDeferredSingleDeclarationErrorCheck) |
1705 | { |
1706 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1707 | recover(); |
1708 | mDeferredSingleDeclarationErrorCheck = false; |
1709 | } |
1710 | |
1711 | if(locationDeclaratorListCheck(identifierLocation, publicType)) |
1712 | recover(); |
1713 | |
1714 | TIntermNode *intermNode = nullptr; |
1715 | if(!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) |
1716 | { |
1717 | // |
1718 | // build the intermediate representation |
1719 | // |
1720 | if(intermNode) |
1721 | { |
1722 | return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation); |
1723 | } |
1724 | else |
1725 | { |
1726 | return aggregateDeclaration; |
1727 | } |
1728 | } |
1729 | else |
1730 | { |
1731 | recover(); |
1732 | return nullptr; |
1733 | } |
1734 | } |
1735 | |
1736 | TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType, |
1737 | TIntermAggregate *aggregateDeclaration, |
1738 | const TSourceLoc &identifierLocation, |
1739 | const TString &identifier, |
1740 | const TSourceLoc &indexLocation, |
1741 | TIntermTyped *indexExpression, |
1742 | const TSourceLoc &initLocation, TIntermTyped *initializer) |
1743 | { |
1744 | // If the declaration starting this declarator list was empty (example: int,), some checks were not performed. |
1745 | if(mDeferredSingleDeclarationErrorCheck) |
1746 | { |
1747 | if(singleDeclarationErrorCheck(publicType, identifierLocation)) |
1748 | recover(); |
1749 | mDeferredSingleDeclarationErrorCheck = false; |
1750 | } |
1751 | |
1752 | if(locationDeclaratorListCheck(identifierLocation, publicType)) |
1753 | recover(); |
1754 | |
1755 | if(arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType)) |
1756 | { |
1757 | recover(); |
1758 | } |
1759 | |
1760 | TPublicType arrayType(publicType); |
1761 | |
1762 | int size = 0; |
1763 | // If indexExpression is nullptr, then the array will eventually get its size implicitly from the initializer. |
1764 | if(indexExpression != nullptr && arraySizeErrorCheck(identifierLocation, indexExpression, size)) |
1765 | { |
1766 | recover(); |
1767 | } |
1768 | // Make the type an array even if size check failed. |
1769 | // This ensures useless error messages regarding the variable's non-arrayness won't follow. |
1770 | arrayType.setArray(true, size); |
1771 | |
1772 | // initNode will correspond to the whole of "b[n] = initializer". |
1773 | TIntermNode *initNode = nullptr; |
1774 | if(!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) |
1775 | { |
1776 | if(initNode) |
1777 | { |
1778 | return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation); |
1779 | } |
1780 | else |
1781 | { |
1782 | return aggregateDeclaration; |
1783 | } |
1784 | } |
1785 | else |
1786 | { |
1787 | recover(); |
1788 | return nullptr; |
1789 | } |
1790 | } |
1791 | |
1792 | void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) |
1793 | { |
1794 | if(mShaderVersion < 300) |
1795 | { |
1796 | error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only" , "layout" ); |
1797 | recover(); |
1798 | return; |
1799 | } |
1800 | |
1801 | if(typeQualifier.qualifier != EvqUniform) |
1802 | { |
1803 | error(typeQualifier.line, "invalid qualifier:" , getQualifierString(typeQualifier.qualifier), "global layout must be uniform" ); |
1804 | recover(); |
1805 | return; |
1806 | } |
1807 | |
1808 | const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; |
1809 | ASSERT(!layoutQualifier.isEmpty()); |
1810 | |
1811 | if(layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier)) |
1812 | { |
1813 | recover(); |
1814 | return; |
1815 | } |
1816 | |
1817 | if(layoutQualifier.matrixPacking != EmpUnspecified) |
1818 | { |
1819 | mDefaultMatrixPacking = layoutQualifier.matrixPacking; |
1820 | } |
1821 | |
1822 | if(layoutQualifier.blockStorage != EbsUnspecified) |
1823 | { |
1824 | mDefaultBlockStorage = layoutQualifier.blockStorage; |
1825 | } |
1826 | } |
1827 | |
1828 | TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function, const TSourceLoc &location) |
1829 | { |
1830 | // Note: symbolTableFunction could be the same as function if this is the first declaration. |
1831 | // Either way the instance in the symbol table is used to track whether the function is declared |
1832 | // multiple times. |
1833 | TFunction *symbolTableFunction = |
1834 | static_cast<TFunction *>(symbolTable.find(function.getMangledName(), getShaderVersion())); |
1835 | if(symbolTableFunction->hasPrototypeDeclaration() && mShaderVersion == 100) |
1836 | { |
1837 | // ESSL 1.00.17 section 4.2.7. |
1838 | // Doesn't apply to ESSL 3.00.4: see section 4.2.3. |
1839 | error(location, "duplicate function prototype declarations are not allowed" , "function" ); |
1840 | recover(); |
1841 | } |
1842 | symbolTableFunction->setHasPrototypeDeclaration(); |
1843 | |
1844 | TIntermAggregate *prototype = new TIntermAggregate; |
1845 | prototype->setType(function.getReturnType()); |
1846 | prototype->setName(function.getMangledName()); |
1847 | |
1848 | for(size_t i = 0; i < function.getParamCount(); i++) |
1849 | { |
1850 | const TParameter ¶m = function.getParam(i); |
1851 | if(param.name != 0) |
1852 | { |
1853 | TVariable variable(param.name, *param.type); |
1854 | |
1855 | TIntermSymbol *paramSymbol = intermediate.addSymbol( |
1856 | variable.getUniqueId(), variable.getName(), variable.getType(), location); |
1857 | prototype = intermediate.growAggregate(prototype, paramSymbol, location); |
1858 | } |
1859 | else |
1860 | { |
1861 | TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "" , *param.type, location); |
1862 | prototype = intermediate.growAggregate(prototype, paramSymbol, location); |
1863 | } |
1864 | } |
1865 | |
1866 | prototype->setOp(EOpPrototype); |
1867 | |
1868 | symbolTable.pop(); |
1869 | |
1870 | if(!symbolTable.atGlobalLevel()) |
1871 | { |
1872 | // ESSL 3.00.4 section 4.2.4. |
1873 | error(location, "local function prototype declarations are not allowed" , "function" ); |
1874 | recover(); |
1875 | } |
1876 | |
1877 | return prototype; |
1878 | } |
1879 | |
1880 | TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function, TIntermAggregate *functionPrototype, TIntermAggregate *functionBody, const TSourceLoc &location) |
1881 | { |
1882 | //?? Check that all paths return a value if return type != void ? |
1883 | // May be best done as post process phase on intermediate code |
1884 | if(mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) |
1885 | { |
1886 | error(location, "function does not return a value:" , "" , function.getName().c_str()); |
1887 | recover(); |
1888 | } |
1889 | |
1890 | TIntermAggregate *aggregate = intermediate.growAggregate(functionPrototype, functionBody, location); |
1891 | intermediate.setAggregateOperator(aggregate, EOpFunction, location); |
1892 | aggregate->setName(function.getMangledName().c_str()); |
1893 | aggregate->setType(function.getReturnType()); |
1894 | |
1895 | // store the pragma information for debug and optimize and other vendor specific |
1896 | // information. This information can be queried from the parse tree |
1897 | aggregate->setOptimize(pragma().optimize); |
1898 | aggregate->setDebug(pragma().debug); |
1899 | |
1900 | if(functionBody && functionBody->getAsAggregate()) |
1901 | aggregate->setEndLine(functionBody->getAsAggregate()->getEndLine()); |
1902 | |
1903 | symbolTable.pop(); |
1904 | return aggregate; |
1905 | } |
1906 | |
1907 | void TParseContext::parseFunctionPrototype(const TSourceLoc &location, TFunction *function, TIntermAggregate **aggregateOut) |
1908 | { |
1909 | const TSymbol *builtIn = symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion()); |
1910 | |
1911 | if(builtIn) |
1912 | { |
1913 | error(location, "built-in functions cannot be redefined" , function->getName().c_str()); |
1914 | recover(); |
1915 | } |
1916 | |
1917 | TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion())); |
1918 | // |
1919 | // Note: 'prevDec' could be 'function' if this is the first time we've seen function |
1920 | // as it would have just been put in the symbol table. Otherwise, we're looking up |
1921 | // an earlier occurance. |
1922 | // |
1923 | if(prevDec->isDefined()) |
1924 | { |
1925 | // Then this function already has a body. |
1926 | error(location, "function already has a body" , function->getName().c_str()); |
1927 | recover(); |
1928 | } |
1929 | prevDec->setDefined(); |
1930 | // |
1931 | // Overload the unique ID of the definition to be the same unique ID as the declaration. |
1932 | // Eventually we will probably want to have only a single definition and just swap the |
1933 | // arguments to be the definition's arguments. |
1934 | // |
1935 | function->setUniqueId(prevDec->getUniqueId()); |
1936 | |
1937 | // Raise error message if main function takes any parameters or return anything other than void |
1938 | if(function->getName() == "main" ) |
1939 | { |
1940 | if(function->getParamCount() > 0) |
1941 | { |
1942 | error(location, "function cannot take any parameter(s)" , function->getName().c_str()); |
1943 | recover(); |
1944 | } |
1945 | if(function->getReturnType().getBasicType() != EbtVoid) |
1946 | { |
1947 | error(location, "" , function->getReturnType().getBasicString(), "main function cannot return a value" ); |
1948 | recover(); |
1949 | } |
1950 | } |
1951 | |
1952 | // |
1953 | // Remember the return type for later checking for RETURN statements. |
1954 | // |
1955 | mCurrentFunctionType = &(prevDec->getReturnType()); |
1956 | mFunctionReturnsValue = false; |
1957 | |
1958 | // |
1959 | // Insert parameters into the symbol table. |
1960 | // If the parameter has no name, it's not an error, just don't insert it |
1961 | // (could be used for unused args). |
1962 | // |
1963 | // Also, accumulate the list of parameters into the HIL, so lower level code |
1964 | // knows where to find parameters. |
1965 | // |
1966 | TIntermAggregate *paramNodes = new TIntermAggregate; |
1967 | for(size_t i = 0; i < function->getParamCount(); i++) |
1968 | { |
1969 | const TParameter ¶m = function->getParam(i); |
1970 | if(param.name != 0) |
1971 | { |
1972 | TVariable *variable = new TVariable(param.name, *param.type); |
1973 | // |
1974 | // Insert the parameters with name in the symbol table. |
1975 | // |
1976 | if(!symbolTable.declare(variable)) |
1977 | { |
1978 | error(location, "redefinition" , variable->getName().c_str()); |
1979 | recover(); |
1980 | paramNodes = intermediate.growAggregate( |
1981 | paramNodes, intermediate.addSymbol(0, "" , *param.type, location), location); |
1982 | continue; |
1983 | } |
1984 | |
1985 | // |
1986 | // Add the parameter to the HIL |
1987 | // |
1988 | TIntermSymbol *symbol = intermediate.addSymbol( |
1989 | variable->getUniqueId(), variable->getName(), variable->getType(), location); |
1990 | |
1991 | paramNodes = intermediate.growAggregate(paramNodes, symbol, location); |
1992 | } |
1993 | else |
1994 | { |
1995 | paramNodes = intermediate.growAggregate( |
1996 | paramNodes, intermediate.addSymbol(0, "" , *param.type, location), location); |
1997 | } |
1998 | } |
1999 | intermediate.setAggregateOperator(paramNodes, EOpParameters, location); |
2000 | *aggregateOut = paramNodes; |
2001 | setLoopNestingLevel(0); |
2002 | } |
2003 | |
2004 | TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function) |
2005 | { |
2006 | // |
2007 | // We don't know at this point whether this is a function definition or a prototype. |
2008 | // The definition production code will check for redefinitions. |
2009 | // In the case of ESSL 1.00 the prototype production code will also check for redeclarations. |
2010 | // |
2011 | // Return types and parameter qualifiers must match in all redeclarations, so those are checked |
2012 | // here. |
2013 | // |
2014 | TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion())); |
2015 | if(getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str())) |
2016 | { |
2017 | // With ESSL 3.00, names of built-in functions cannot be redeclared as functions. |
2018 | // Therefore overloading or redefining builtin functions is an error. |
2019 | error(location, "Name of a built-in function cannot be redeclared as function" , function->getName().c_str()); |
2020 | } |
2021 | else if(prevDec) |
2022 | { |
2023 | if(prevDec->getReturnType() != function->getReturnType()) |
2024 | { |
2025 | error(location, "overloaded functions must have the same return type" , |
2026 | function->getReturnType().getBasicString()); |
2027 | recover(); |
2028 | } |
2029 | for(size_t i = 0; i < prevDec->getParamCount(); ++i) |
2030 | { |
2031 | if(prevDec->getParam(i).type->getQualifier() != function->getParam(i).type->getQualifier()) |
2032 | { |
2033 | error(location, "overloaded functions must have the same parameter qualifiers" , |
2034 | function->getParam(i).type->getQualifierString()); |
2035 | recover(); |
2036 | } |
2037 | } |
2038 | } |
2039 | |
2040 | // |
2041 | // Check for previously declared variables using the same name. |
2042 | // |
2043 | TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion()); |
2044 | if(prevSym) |
2045 | { |
2046 | if(!prevSym->isFunction()) |
2047 | { |
2048 | error(location, "redefinition" , function->getName().c_str(), "function" ); |
2049 | recover(); |
2050 | } |
2051 | } |
2052 | else |
2053 | { |
2054 | // Insert the unmangled name to detect potential future redefinition as a variable. |
2055 | TFunction *unmangledFunction = new TFunction(NewPoolTString(function->getName().c_str()), function->getReturnType()); |
2056 | symbolTable.getOuterLevel()->insertUnmangled(unmangledFunction); |
2057 | } |
2058 | |
2059 | // We're at the inner scope level of the function's arguments and body statement. |
2060 | // Add the function prototype to the surrounding scope instead. |
2061 | symbolTable.getOuterLevel()->insert(function); |
2062 | |
2063 | // |
2064 | // If this is a redeclaration, it could also be a definition, in which case, we want to use the |
2065 | // variable names from this one, and not the one that's |
2066 | // being redeclared. So, pass back up this declaration, not the one in the symbol table. |
2067 | // |
2068 | return function; |
2069 | } |
2070 | |
2071 | TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) |
2072 | { |
2073 | TPublicType publicType = publicTypeIn; |
2074 | TOperator op = EOpNull; |
2075 | if(publicType.userDef) |
2076 | { |
2077 | op = EOpConstructStruct; |
2078 | } |
2079 | else |
2080 | { |
2081 | op = TypeToConstructorOperator(TType(publicType)); |
2082 | if(op == EOpNull) |
2083 | { |
2084 | error(publicType.line, "cannot construct this type" , getBasicString(publicType.type)); |
2085 | recover(); |
2086 | publicType.type = EbtFloat; |
2087 | op = EOpConstructFloat; |
2088 | } |
2089 | } |
2090 | |
2091 | TString tempString; |
2092 | TType type(publicType); |
2093 | return new TFunction(&tempString, type, op); |
2094 | } |
2095 | |
2096 | // This function is used to test for the correctness of the parameters passed to various constructor functions |
2097 | // and also convert them to the right datatype if it is allowed and required. |
2098 | // |
2099 | // Returns 0 for an error or the constructed node (aggregate or typed) for no error. |
2100 | // |
2101 | TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc &line) |
2102 | { |
2103 | TIntermAggregate *aggregateArguments = arguments->getAsAggregate(); |
2104 | |
2105 | if(!aggregateArguments) |
2106 | { |
2107 | aggregateArguments = new TIntermAggregate; |
2108 | aggregateArguments->getSequence().push_back(arguments); |
2109 | } |
2110 | |
2111 | if(type->isArray()) |
2112 | { |
2113 | // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of |
2114 | // the array. |
2115 | for(TIntermNode *&argNode : aggregateArguments->getSequence()) |
2116 | { |
2117 | const TType &argType = argNode->getAsTyped()->getType(); |
2118 | // It has already been checked that the argument is not an array. |
2119 | ASSERT(!argType.isArray()); |
2120 | if(!argType.sameElementType(*type)) |
2121 | { |
2122 | error(line, "Array constructor argument has an incorrect type" , "Error" ); |
2123 | return nullptr; |
2124 | } |
2125 | } |
2126 | } |
2127 | else if(op == EOpConstructStruct) |
2128 | { |
2129 | const TFieldList &fields = type->getStruct()->fields(); |
2130 | TIntermSequence &args = aggregateArguments->getSequence(); |
2131 | |
2132 | for(size_t i = 0; i < fields.size(); i++) |
2133 | { |
2134 | if(args[i]->getAsTyped()->getType() != *fields[i]->type()) |
2135 | { |
2136 | error(line, "Structure constructor arguments do not match structure fields" , "Error" ); |
2137 | recover(); |
2138 | |
2139 | return nullptr; |
2140 | } |
2141 | } |
2142 | } |
2143 | |
2144 | // Turn the argument list itself into a constructor |
2145 | TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); |
2146 | TIntermTyped *constConstructor = foldConstConstructor(constructor, *type); |
2147 | if(constConstructor) |
2148 | { |
2149 | return constConstructor; |
2150 | } |
2151 | |
2152 | return constructor; |
2153 | } |
2154 | |
2155 | TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) |
2156 | { |
2157 | aggrNode->setType(type); |
2158 | if (aggrNode->isConstantFoldable()) { |
2159 | bool returnVal = false; |
2160 | ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; |
2161 | if (aggrNode->getSequence().size() == 1) { |
2162 | returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true); |
2163 | } |
2164 | else { |
2165 | returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type); |
2166 | } |
2167 | if (returnVal) |
2168 | return nullptr; |
2169 | |
2170 | return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); |
2171 | } |
2172 | |
2173 | return nullptr; |
2174 | } |
2175 | |
2176 | // |
2177 | // This function returns the tree representation for the vector field(s) being accessed from contant vector. |
2178 | // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is |
2179 | // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol |
2180 | // node or it could be the intermediate tree representation of accessing fields in a constant structure or column of |
2181 | // a constant matrix. |
2182 | // |
2183 | TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc &line) |
2184 | { |
2185 | TIntermTyped* typedNode; |
2186 | TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); |
2187 | |
2188 | ConstantUnion *unionArray; |
2189 | if (tempConstantNode) { |
2190 | unionArray = tempConstantNode->getUnionArrayPointer(); |
2191 | |
2192 | if (!unionArray) { |
2193 | return node; |
2194 | } |
2195 | } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error |
2196 | error(line, "Cannot offset into the vector" , "Error" ); |
2197 | recover(); |
2198 | |
2199 | return nullptr; |
2200 | } |
2201 | |
2202 | ConstantUnion* constArray = new ConstantUnion[fields.num]; |
2203 | |
2204 | int objSize = static_cast<int>(node->getType().getObjectSize()); |
2205 | for (int i = 0; i < fields.num; i++) { |
2206 | if (fields.offsets[i] >= objSize) { |
2207 | std::stringstream ; |
2208 | extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'" ; |
2209 | std::string = extraInfoStream.str(); |
2210 | error(line, "" , "[" , extraInfo.c_str()); |
2211 | recover(); |
2212 | fields.offsets[i] = 0; |
2213 | } |
2214 | |
2215 | constArray[i] = unionArray[fields.offsets[i]]; |
2216 | |
2217 | } |
2218 | |
2219 | TType type(node->getType().getBasicType(), node->getType().getPrecision(), EvqConstExpr, fields.num); |
2220 | typedNode = intermediate.addConstantUnion(constArray, type, line); |
2221 | return typedNode; |
2222 | } |
2223 | |
2224 | // |
2225 | // This function returns the column being accessed from a constant matrix. The values are retrieved from |
2226 | // the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input |
2227 | // to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a |
2228 | // constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) |
2229 | // |
2230 | TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc &line) |
2231 | { |
2232 | TIntermTyped* typedNode; |
2233 | TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); |
2234 | |
2235 | if (index >= node->getType().getNominalSize()) { |
2236 | std::stringstream ; |
2237 | extraInfoStream << "matrix field selection out of range '" << index << "'" ; |
2238 | std::string = extraInfoStream.str(); |
2239 | error(line, "" , "[" , extraInfo.c_str()); |
2240 | recover(); |
2241 | index = 0; |
2242 | } |
2243 | |
2244 | if (tempConstantNode) { |
2245 | ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); |
2246 | int size = tempConstantNode->getType().getNominalSize(); |
2247 | typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); |
2248 | } else { |
2249 | error(line, "Cannot offset into the matrix" , "Error" ); |
2250 | recover(); |
2251 | |
2252 | return nullptr; |
2253 | } |
2254 | |
2255 | return typedNode; |
2256 | } |
2257 | |
2258 | |
2259 | // |
2260 | // This function returns an element of an array accessed from a constant array. The values are retrieved from |
2261 | // the symbol table and parse-tree is built for the type of the element. The input |
2262 | // to the function could either be a symbol node (a[0] where a is a constant array)that represents a |
2263 | // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) |
2264 | // |
2265 | TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc &line) |
2266 | { |
2267 | TIntermTyped* typedNode; |
2268 | TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); |
2269 | TType arrayElementType = node->getType(); |
2270 | arrayElementType.clearArrayness(); |
2271 | |
2272 | if (index >= node->getType().getArraySize()) { |
2273 | std::stringstream ; |
2274 | extraInfoStream << "array field selection out of range '" << index << "'" ; |
2275 | std::string = extraInfoStream.str(); |
2276 | error(line, "" , "[" , extraInfo.c_str()); |
2277 | recover(); |
2278 | index = 0; |
2279 | } |
2280 | |
2281 | size_t arrayElementSize = arrayElementType.getObjectSize(); |
2282 | |
2283 | if (tempConstantNode) { |
2284 | ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); |
2285 | typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); |
2286 | } else { |
2287 | error(line, "Cannot offset into the array" , "Error" ); |
2288 | recover(); |
2289 | |
2290 | return nullptr; |
2291 | } |
2292 | |
2293 | return typedNode; |
2294 | } |
2295 | |
2296 | |
2297 | // |
2298 | // This function returns the value of a particular field inside a constant structure from the symbol table. |
2299 | // If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr |
2300 | // function and returns the parse-tree with the values of the embedded/nested struct. |
2301 | // |
2302 | TIntermTyped* TParseContext::addConstStruct(const TString& identifier, TIntermTyped* node, const TSourceLoc &line) |
2303 | { |
2304 | const TFieldList &fields = node->getType().getStruct()->fields(); |
2305 | TIntermTyped *typedNode; |
2306 | size_t instanceSize = 0; |
2307 | TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); |
2308 | |
2309 | for(const auto &field : fields) { |
2310 | if (field->name() == identifier) { |
2311 | break; |
2312 | } else { |
2313 | instanceSize += field->type()->getObjectSize(); |
2314 | } |
2315 | } |
2316 | |
2317 | if (tempConstantNode) { |
2318 | ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); |
2319 | |
2320 | typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function |
2321 | } else { |
2322 | error(line, "Cannot offset into the structure" , "Error" ); |
2323 | recover(); |
2324 | |
2325 | return nullptr; |
2326 | } |
2327 | |
2328 | return typedNode; |
2329 | } |
2330 | |
2331 | // |
2332 | // Interface/uniform blocks |
2333 | // |
2334 | TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList, |
2335 | const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine) |
2336 | { |
2337 | if(reservedErrorCheck(nameLine, blockName)) |
2338 | recover(); |
2339 | |
2340 | if(typeQualifier.qualifier != EvqUniform) |
2341 | { |
2342 | error(typeQualifier.line, "invalid qualifier:" , getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform" ); |
2343 | recover(); |
2344 | } |
2345 | |
2346 | TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; |
2347 | if(layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier)) |
2348 | { |
2349 | recover(); |
2350 | } |
2351 | |
2352 | if(blockLayoutQualifier.matrixPacking == EmpUnspecified) |
2353 | { |
2354 | blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking; |
2355 | } |
2356 | |
2357 | if(blockLayoutQualifier.blockStorage == EbsUnspecified) |
2358 | { |
2359 | blockLayoutQualifier.blockStorage = mDefaultBlockStorage; |
2360 | } |
2361 | |
2362 | TSymbol* blockNameSymbol = new TSymbol(&blockName); |
2363 | if(!symbolTable.declare(blockNameSymbol)) { |
2364 | error(nameLine, "redefinition" , blockName.c_str(), "interface block name" ); |
2365 | recover(); |
2366 | } |
2367 | |
2368 | // check for sampler types and apply layout qualifiers |
2369 | for(const auto &field : *fieldList) { |
2370 | TType* fieldType = field->type(); |
2371 | if(IsSampler(fieldType->getBasicType())) { |
2372 | error(field->line(), "unsupported type" , fieldType->getBasicString(), "sampler types are not allowed in interface blocks" ); |
2373 | recover(); |
2374 | } |
2375 | |
2376 | const TQualifier qualifier = fieldType->getQualifier(); |
2377 | switch(qualifier) |
2378 | { |
2379 | case EvqGlobal: |
2380 | case EvqUniform: |
2381 | break; |
2382 | default: |
2383 | error(field->line(), "invalid qualifier on interface block member" , getQualifierString(qualifier)); |
2384 | recover(); |
2385 | break; |
2386 | } |
2387 | |
2388 | // check layout qualifiers |
2389 | TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); |
2390 | if(layoutLocationErrorCheck(field->line(), fieldLayoutQualifier)) |
2391 | { |
2392 | recover(); |
2393 | } |
2394 | |
2395 | if(fieldLayoutQualifier.blockStorage != EbsUnspecified) |
2396 | { |
2397 | error(field->line(), "invalid layout qualifier:" , getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here" ); |
2398 | recover(); |
2399 | } |
2400 | |
2401 | if(fieldLayoutQualifier.matrixPacking == EmpUnspecified) |
2402 | { |
2403 | fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; |
2404 | } |
2405 | else if(!fieldType->isMatrix() && (fieldType->getBasicType() != EbtStruct)) |
2406 | { |
2407 | warning(field->line(), "extraneous layout qualifier:" , getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "only has an effect on matrix types" ); |
2408 | } |
2409 | |
2410 | fieldType->setLayoutQualifier(fieldLayoutQualifier); |
2411 | |
2412 | // Recursively propagate the matrix packing setting down to all block/structure members |
2413 | fieldType->setMatrixPackingIfUnspecified(fieldLayoutQualifier.matrixPacking); |
2414 | } |
2415 | |
2416 | // add array index |
2417 | int arraySize = 0; |
2418 | if(arrayIndex) |
2419 | { |
2420 | if(arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize)) |
2421 | recover(); |
2422 | } |
2423 | |
2424 | TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier); |
2425 | TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize); |
2426 | |
2427 | TString symbolName = "" ; |
2428 | int symbolId = 0; |
2429 | |
2430 | if(!instanceName) |
2431 | { |
2432 | // define symbols for the members of the interface block |
2433 | for(const auto &field : *fieldList) |
2434 | { |
2435 | TType* fieldType = field->type(); |
2436 | |
2437 | // set parent pointer of the field variable |
2438 | fieldType->setInterfaceBlock(interfaceBlock); |
2439 | |
2440 | TVariable* fieldVariable = new TVariable(&field->name(), *fieldType); |
2441 | fieldVariable->setQualifier(typeQualifier.qualifier); |
2442 | |
2443 | if(!symbolTable.declare(fieldVariable)) { |
2444 | error(field->line(), "redefinition" , field->name().c_str(), "interface block member name" ); |
2445 | recover(); |
2446 | } |
2447 | } |
2448 | } |
2449 | else |
2450 | { |
2451 | if(reservedErrorCheck(nameLine, *instanceName)) |
2452 | recover(); |
2453 | |
2454 | // add a symbol for this interface block |
2455 | TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false); |
2456 | instanceTypeDef->setQualifier(typeQualifier.qualifier); |
2457 | |
2458 | if(!symbolTable.declare(instanceTypeDef)) { |
2459 | error(instanceLine, "redefinition" , instanceName->c_str(), "interface block instance name" ); |
2460 | recover(); |
2461 | } |
2462 | |
2463 | symbolId = instanceTypeDef->getUniqueId(); |
2464 | symbolName = instanceTypeDef->getName(); |
2465 | } |
2466 | |
2467 | TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine); |
2468 | aggregate->setOp(EOpDeclaration); |
2469 | |
2470 | exitStructDeclaration(); |
2471 | return aggregate; |
2472 | } |
2473 | |
2474 | // |
2475 | // Parse an array index expression |
2476 | // |
2477 | TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc &location, TIntermTyped *indexExpression) |
2478 | { |
2479 | TIntermTyped *indexedExpression = nullptr; |
2480 | |
2481 | if(!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) |
2482 | { |
2483 | if(baseExpression->getAsSymbolNode()) |
2484 | { |
2485 | error(location, " left of '[' is not of type array, matrix, or vector " , |
2486 | baseExpression->getAsSymbolNode()->getSymbol().c_str()); |
2487 | } |
2488 | else |
2489 | { |
2490 | error(location, " left of '[' is not of type array, matrix, or vector " , "expression" ); |
2491 | } |
2492 | recover(); |
2493 | } |
2494 | |
2495 | TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); |
2496 | |
2497 | if(indexExpression->getQualifier() == EvqConstExpr && indexConstantUnion) // TODO: Qualifier check redundant? |
2498 | { |
2499 | int index = indexConstantUnion->getIConst(0); |
2500 | if(index < 0) |
2501 | { |
2502 | std::stringstream infoStream; |
2503 | infoStream << index; |
2504 | std::string info = infoStream.str(); |
2505 | error(location, "negative index" , info.c_str()); |
2506 | recover(); |
2507 | index = 0; |
2508 | } |
2509 | if(baseExpression->getType().getQualifier() == EvqConstExpr && baseExpression->getAsConstantUnion()) // TODO: Qualifier check redundant? |
2510 | { |
2511 | if(baseExpression->isArray()) |
2512 | { |
2513 | // constant folding for arrays |
2514 | indexedExpression = addConstArrayNode(index, baseExpression, location); |
2515 | } |
2516 | else if(baseExpression->isVector()) |
2517 | { |
2518 | // constant folding for vectors |
2519 | TVectorFields fields; |
2520 | fields.num = 1; |
2521 | fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array |
2522 | indexedExpression = addConstVectorNode(fields, baseExpression, location); |
2523 | } |
2524 | else if(baseExpression->isMatrix()) |
2525 | { |
2526 | // constant folding for matrices |
2527 | indexedExpression = addConstMatrixNode(index, baseExpression, location); |
2528 | } |
2529 | } |
2530 | else |
2531 | { |
2532 | int safeIndex = -1; |
2533 | |
2534 | if(baseExpression->isArray()) |
2535 | { |
2536 | if(index >= baseExpression->getType().getArraySize()) |
2537 | { |
2538 | std::stringstream ; |
2539 | extraInfoStream << "array index out of range '" << index << "'" ; |
2540 | std::string = extraInfoStream.str(); |
2541 | error(location, "" , "[" , extraInfo.c_str()); |
2542 | recover(); |
2543 | safeIndex = baseExpression->getType().getArraySize() - 1; |
2544 | } |
2545 | } |
2546 | else if((baseExpression->isVector() || baseExpression->isMatrix()) && |
2547 | baseExpression->getType().getNominalSize() <= index) |
2548 | { |
2549 | std::stringstream ; |
2550 | extraInfoStream << "field selection out of range '" << index << "'" ; |
2551 | std::string = extraInfoStream.str(); |
2552 | error(location, "" , "[" , extraInfo.c_str()); |
2553 | recover(); |
2554 | safeIndex = baseExpression->getType().getNominalSize() - 1; |
2555 | } |
2556 | |
2557 | // Don't modify the data of the previous constant union, because it can point |
2558 | // to builtins, like gl_MaxDrawBuffers. Instead use a new sanitized object. |
2559 | if(safeIndex != -1) |
2560 | { |
2561 | ConstantUnion *safeConstantUnion = new ConstantUnion(); |
2562 | safeConstantUnion->setIConst(safeIndex); |
2563 | indexConstantUnion->replaceConstantUnion(safeConstantUnion); |
2564 | } |
2565 | |
2566 | indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); |
2567 | } |
2568 | } |
2569 | else |
2570 | { |
2571 | if(baseExpression->isInterfaceBlock()) |
2572 | { |
2573 | error(location, "" , |
2574 | "[" , "array indexes for interface blocks arrays must be constant integral expressions" ); |
2575 | recover(); |
2576 | } |
2577 | else if(baseExpression->getQualifier() == EvqFragmentOut) |
2578 | { |
2579 | error(location, "" , "[" , "array indexes for fragment outputs must be constant integral expressions" ); |
2580 | recover(); |
2581 | } |
2582 | |
2583 | indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); |
2584 | } |
2585 | |
2586 | if(indexedExpression == 0) |
2587 | { |
2588 | ConstantUnion *unionArray = new ConstantUnion[1]; |
2589 | unionArray->setFConst(0.0f); |
2590 | indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConstExpr), location); |
2591 | } |
2592 | else if(baseExpression->isArray()) |
2593 | { |
2594 | const TType &baseType = baseExpression->getType(); |
2595 | if(baseType.getStruct()) |
2596 | { |
2597 | TType copyOfType(baseType.getStruct()); |
2598 | indexedExpression->setType(copyOfType); |
2599 | } |
2600 | else if(baseType.isInterfaceBlock()) |
2601 | { |
2602 | TType copyOfType(baseType.getInterfaceBlock(), EvqTemporary, baseType.getLayoutQualifier(), 0); |
2603 | indexedExpression->setType(copyOfType); |
2604 | } |
2605 | else |
2606 | { |
2607 | indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), |
2608 | EvqTemporary, static_cast<unsigned char>(baseExpression->getNominalSize()), |
2609 | static_cast<unsigned char>(baseExpression->getSecondarySize()))); |
2610 | } |
2611 | |
2612 | if(baseExpression->getType().getQualifier() == EvqConstExpr) |
2613 | { |
2614 | indexedExpression->getTypePointer()->setQualifier(EvqConstExpr); |
2615 | } |
2616 | } |
2617 | else if(baseExpression->isMatrix()) |
2618 | { |
2619 | TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConstExpr ? EvqConstExpr : EvqTemporary; |
2620 | indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), |
2621 | qualifier, static_cast<unsigned char>(baseExpression->getSecondarySize()))); |
2622 | } |
2623 | else if(baseExpression->isVector()) |
2624 | { |
2625 | TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConstExpr ? EvqConstExpr : EvqTemporary; |
2626 | indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier)); |
2627 | } |
2628 | else |
2629 | { |
2630 | indexedExpression->setType(baseExpression->getType()); |
2631 | } |
2632 | |
2633 | return indexedExpression; |
2634 | } |
2635 | |
2636 | TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc &dotLocation, |
2637 | const TString &fieldString, const TSourceLoc &fieldLocation) |
2638 | { |
2639 | TIntermTyped *indexedExpression = nullptr; |
2640 | |
2641 | if(baseExpression->isArray()) |
2642 | { |
2643 | error(fieldLocation, "cannot apply dot operator to an array" , "." ); |
2644 | recover(); |
2645 | } |
2646 | |
2647 | if(baseExpression->isVector()) |
2648 | { |
2649 | TVectorFields fields; |
2650 | if(!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation)) |
2651 | { |
2652 | fields.num = 1; |
2653 | fields.offsets[0] = 0; |
2654 | recover(); |
2655 | } |
2656 | |
2657 | if(baseExpression->getAsConstantUnion()) |
2658 | { |
2659 | // constant folding for vector fields |
2660 | indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation); |
2661 | if(indexedExpression == 0) |
2662 | { |
2663 | recover(); |
2664 | indexedExpression = baseExpression; |
2665 | } |
2666 | } |
2667 | else |
2668 | { |
2669 | TString vectorString = fieldString; |
2670 | TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation); |
2671 | indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation); |
2672 | indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), |
2673 | baseExpression->getQualifier() == EvqConstExpr ? EvqConstExpr : EvqTemporary, (unsigned char)vectorString.size())); |
2674 | } |
2675 | } |
2676 | else if(baseExpression->getBasicType() == EbtStruct) |
2677 | { |
2678 | bool fieldFound = false; |
2679 | const TFieldList &fields = baseExpression->getType().getStruct()->fields(); |
2680 | if(fields.empty()) |
2681 | { |
2682 | error(dotLocation, "structure has no fields" , "Internal Error" ); |
2683 | recover(); |
2684 | indexedExpression = baseExpression; |
2685 | } |
2686 | else |
2687 | { |
2688 | unsigned int i; |
2689 | for(i = 0; i < fields.size(); ++i) |
2690 | { |
2691 | if(fields[i]->name() == fieldString) |
2692 | { |
2693 | fieldFound = true; |
2694 | break; |
2695 | } |
2696 | } |
2697 | if(fieldFound) |
2698 | { |
2699 | if(baseExpression->getType().getQualifier() == EvqConstExpr) |
2700 | { |
2701 | indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation); |
2702 | if(indexedExpression == 0) |
2703 | { |
2704 | recover(); |
2705 | indexedExpression = baseExpression; |
2706 | } |
2707 | else |
2708 | { |
2709 | indexedExpression->setType(*fields[i]->type()); |
2710 | // change the qualifier of the return type, not of the structure field |
2711 | // as the structure definition is shared between various structures. |
2712 | indexedExpression->getTypePointer()->setQualifier(EvqConstExpr); |
2713 | } |
2714 | } |
2715 | else |
2716 | { |
2717 | TIntermTyped *index = TIntermTyped::CreateIndexNode(i); |
2718 | index->setLine(fieldLocation); |
2719 | indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation); |
2720 | indexedExpression->setType(*fields[i]->type()); |
2721 | } |
2722 | } |
2723 | else |
2724 | { |
2725 | error(dotLocation, " no such field in structure" , fieldString.c_str()); |
2726 | recover(); |
2727 | indexedExpression = baseExpression; |
2728 | } |
2729 | } |
2730 | } |
2731 | else if(baseExpression->isInterfaceBlock()) |
2732 | { |
2733 | bool fieldFound = false; |
2734 | const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); |
2735 | if(fields.empty()) |
2736 | { |
2737 | error(dotLocation, "interface block has no fields" , "Internal Error" ); |
2738 | recover(); |
2739 | indexedExpression = baseExpression; |
2740 | } |
2741 | else |
2742 | { |
2743 | unsigned int i; |
2744 | for(i = 0; i < fields.size(); ++i) |
2745 | { |
2746 | if(fields[i]->name() == fieldString) |
2747 | { |
2748 | fieldFound = true; |
2749 | break; |
2750 | } |
2751 | } |
2752 | if(fieldFound) |
2753 | { |
2754 | ConstantUnion *unionArray = new ConstantUnion[1]; |
2755 | unionArray->setIConst(i); |
2756 | TIntermTyped *index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); |
2757 | indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, |
2758 | dotLocation); |
2759 | indexedExpression->setType(*fields[i]->type()); |
2760 | } |
2761 | else |
2762 | { |
2763 | error(dotLocation, " no such field in interface block" , fieldString.c_str()); |
2764 | recover(); |
2765 | indexedExpression = baseExpression; |
2766 | } |
2767 | } |
2768 | } |
2769 | else |
2770 | { |
2771 | if(mShaderVersion < 300) |
2772 | { |
2773 | error(dotLocation, " field selection requires structure or vector on left hand side" , |
2774 | fieldString.c_str()); |
2775 | } |
2776 | else |
2777 | { |
2778 | error(dotLocation, |
2779 | " field selection requires structure, vector, or interface block on left hand side" , |
2780 | fieldString.c_str()); |
2781 | } |
2782 | recover(); |
2783 | indexedExpression = baseExpression; |
2784 | } |
2785 | |
2786 | return indexedExpression; |
2787 | } |
2788 | |
2789 | TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine) |
2790 | { |
2791 | TLayoutQualifier qualifier; |
2792 | |
2793 | qualifier.location = -1; |
2794 | qualifier.matrixPacking = EmpUnspecified; |
2795 | qualifier.blockStorage = EbsUnspecified; |
2796 | |
2797 | if(qualifierType == "shared" ) |
2798 | { |
2799 | qualifier.blockStorage = EbsShared; |
2800 | } |
2801 | else if(qualifierType == "packed" ) |
2802 | { |
2803 | qualifier.blockStorage = EbsPacked; |
2804 | } |
2805 | else if(qualifierType == "std140" ) |
2806 | { |
2807 | qualifier.blockStorage = EbsStd140; |
2808 | } |
2809 | else if(qualifierType == "row_major" ) |
2810 | { |
2811 | qualifier.matrixPacking = EmpRowMajor; |
2812 | } |
2813 | else if(qualifierType == "column_major" ) |
2814 | { |
2815 | qualifier.matrixPacking = EmpColumnMajor; |
2816 | } |
2817 | else if(qualifierType == "location" ) |
2818 | { |
2819 | error(qualifierTypeLine, "invalid layout qualifier" , qualifierType.c_str(), "location requires an argument" ); |
2820 | recover(); |
2821 | } |
2822 | else |
2823 | { |
2824 | error(qualifierTypeLine, "invalid layout qualifier" , qualifierType.c_str()); |
2825 | recover(); |
2826 | } |
2827 | |
2828 | return qualifier; |
2829 | } |
2830 | |
2831 | TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, int intValue, const TSourceLoc& intValueLine) |
2832 | { |
2833 | TLayoutQualifier qualifier; |
2834 | |
2835 | qualifier.location = -1; // -1 isn't a valid location, it means the value isn't set. Negative values are checked lower in this function. |
2836 | qualifier.matrixPacking = EmpUnspecified; |
2837 | qualifier.blockStorage = EbsUnspecified; |
2838 | |
2839 | if (qualifierType != "location" ) |
2840 | { |
2841 | error(qualifierTypeLine, "invalid layout qualifier" , qualifierType.c_str(), "only location may have arguments" ); |
2842 | recover(); |
2843 | } |
2844 | else |
2845 | { |
2846 | // must check that location is non-negative |
2847 | if (intValue < 0) |
2848 | { |
2849 | error(intValueLine, "out of range:" , "" , "location must be non-negative" ); |
2850 | recover(); |
2851 | } |
2852 | else |
2853 | { |
2854 | qualifier.location = intValue; |
2855 | } |
2856 | } |
2857 | |
2858 | return qualifier; |
2859 | } |
2860 | |
2861 | TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier) |
2862 | { |
2863 | TLayoutQualifier joinedQualifier = leftQualifier; |
2864 | |
2865 | if (rightQualifier.location != -1) |
2866 | { |
2867 | joinedQualifier.location = rightQualifier.location; |
2868 | } |
2869 | if(rightQualifier.matrixPacking != EmpUnspecified) |
2870 | { |
2871 | joinedQualifier.matrixPacking = rightQualifier.matrixPacking; |
2872 | } |
2873 | if(rightQualifier.blockStorage != EbsUnspecified) |
2874 | { |
2875 | joinedQualifier.blockStorage = rightQualifier.blockStorage; |
2876 | } |
2877 | |
2878 | return joinedQualifier; |
2879 | } |
2880 | |
2881 | |
2882 | TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, |
2883 | const TSourceLoc &storageLoc, TQualifier storageQualifier) |
2884 | { |
2885 | TQualifier mergedQualifier = EvqSmoothIn; |
2886 | |
2887 | if(storageQualifier == EvqFragmentIn) { |
2888 | if(interpolationQualifier == EvqSmooth) |
2889 | mergedQualifier = EvqSmoothIn; |
2890 | else if(interpolationQualifier == EvqFlat) |
2891 | mergedQualifier = EvqFlatIn; |
2892 | else UNREACHABLE(interpolationQualifier); |
2893 | } |
2894 | else if(storageQualifier == EvqCentroidIn) { |
2895 | if(interpolationQualifier == EvqSmooth) |
2896 | mergedQualifier = EvqCentroidIn; |
2897 | else if(interpolationQualifier == EvqFlat) |
2898 | mergedQualifier = EvqFlatIn; |
2899 | else UNREACHABLE(interpolationQualifier); |
2900 | } |
2901 | else if(storageQualifier == EvqVertexOut) { |
2902 | if(interpolationQualifier == EvqSmooth) |
2903 | mergedQualifier = EvqSmoothOut; |
2904 | else if(interpolationQualifier == EvqFlat) |
2905 | mergedQualifier = EvqFlatOut; |
2906 | else UNREACHABLE(interpolationQualifier); |
2907 | } |
2908 | else if(storageQualifier == EvqCentroidOut) { |
2909 | if(interpolationQualifier == EvqSmooth) |
2910 | mergedQualifier = EvqCentroidOut; |
2911 | else if(interpolationQualifier == EvqFlat) |
2912 | mergedQualifier = EvqFlatOut; |
2913 | else UNREACHABLE(interpolationQualifier); |
2914 | } |
2915 | else { |
2916 | error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier" , getQualifierString(interpolationQualifier)); |
2917 | recover(); |
2918 | |
2919 | mergedQualifier = storageQualifier; |
2920 | } |
2921 | |
2922 | TPublicType type; |
2923 | type.setBasic(EbtVoid, mergedQualifier, storageLoc); |
2924 | return type; |
2925 | } |
2926 | |
2927 | TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList) |
2928 | { |
2929 | if(voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type)) |
2930 | { |
2931 | recover(); |
2932 | } |
2933 | |
2934 | for(const auto &field : *fieldList) |
2935 | { |
2936 | // |
2937 | // Careful not to replace already known aspects of type, like array-ness |
2938 | // |
2939 | TType *type = field->type(); |
2940 | type->setBasicType(typeSpecifier.type); |
2941 | type->setNominalSize(typeSpecifier.primarySize); |
2942 | type->setSecondarySize(typeSpecifier.secondarySize); |
2943 | type->setPrecision(typeSpecifier.precision); |
2944 | type->setQualifier(typeSpecifier.qualifier); |
2945 | type->setLayoutQualifier(typeSpecifier.layoutQualifier); |
2946 | |
2947 | // don't allow arrays of arrays |
2948 | if(type->isArray()) |
2949 | { |
2950 | if(arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier)) |
2951 | recover(); |
2952 | } |
2953 | if(typeSpecifier.array) |
2954 | type->setArraySize(typeSpecifier.arraySize); |
2955 | if(typeSpecifier.userDef) |
2956 | { |
2957 | type->setStruct(typeSpecifier.userDef->getStruct()); |
2958 | } |
2959 | |
2960 | if(structNestingErrorCheck(typeSpecifier.line, *field)) |
2961 | { |
2962 | recover(); |
2963 | } |
2964 | } |
2965 | |
2966 | return fieldList; |
2967 | } |
2968 | |
2969 | TPublicType TParseContext::addStructure(const TSourceLoc &structLine, const TSourceLoc &nameLine, |
2970 | const TString *structName, TFieldList *fieldList) |
2971 | { |
2972 | TStructure *structure = new TStructure(structName, fieldList); |
2973 | TType *structureType = new TType(structure); |
2974 | |
2975 | // Store a bool in the struct if we're at global scope, to allow us to |
2976 | // skip the local struct scoping workaround in HLSL. |
2977 | structure->setUniqueId(TSymbolTableLevel::nextUniqueId()); |
2978 | structure->setAtGlobalScope(symbolTable.atGlobalLevel()); |
2979 | |
2980 | if(!structName->empty()) |
2981 | { |
2982 | if(reservedErrorCheck(nameLine, *structName)) |
2983 | { |
2984 | recover(); |
2985 | } |
2986 | TVariable *userTypeDef = new TVariable(structName, *structureType, true); |
2987 | if(!symbolTable.declare(userTypeDef)) |
2988 | { |
2989 | error(nameLine, "redefinition" , structName->c_str(), "struct" ); |
2990 | recover(); |
2991 | } |
2992 | } |
2993 | |
2994 | // ensure we do not specify any storage qualifiers on the struct members |
2995 | for(const auto &field : *fieldList) |
2996 | { |
2997 | const TQualifier qualifier = field->type()->getQualifier(); |
2998 | switch(qualifier) |
2999 | { |
3000 | case EvqGlobal: |
3001 | case EvqTemporary: |
3002 | break; |
3003 | default: |
3004 | error(field->line(), "invalid qualifier on struct member" , getQualifierString(qualifier)); |
3005 | recover(); |
3006 | break; |
3007 | } |
3008 | } |
3009 | |
3010 | TPublicType publicType; |
3011 | publicType.setBasic(EbtStruct, EvqTemporary, structLine); |
3012 | publicType.userDef = structureType; |
3013 | exitStructDeclaration(); |
3014 | |
3015 | return publicType; |
3016 | } |
3017 | |
3018 | bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString& identifier) |
3019 | { |
3020 | ++mStructNestingLevel; |
3021 | |
3022 | // Embedded structure definitions are not supported per GLSL ES spec. |
3023 | // They aren't allowed in GLSL either, but we need to detect this here |
3024 | // so we don't rely on the GLSL compiler to catch it. |
3025 | if (mStructNestingLevel > 1) { |
3026 | error(line, "" , "Embedded struct definitions are not allowed" ); |
3027 | return true; |
3028 | } |
3029 | |
3030 | return false; |
3031 | } |
3032 | |
3033 | void TParseContext::exitStructDeclaration() |
3034 | { |
3035 | --mStructNestingLevel; |
3036 | } |
3037 | |
3038 | bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field) |
3039 | { |
3040 | static const int kWebGLMaxStructNesting = 4; |
3041 | |
3042 | if(field.type()->getBasicType() != EbtStruct) |
3043 | { |
3044 | return false; |
3045 | } |
3046 | |
3047 | // We're already inside a structure definition at this point, so add |
3048 | // one to the field's struct nesting. |
3049 | if(1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) |
3050 | { |
3051 | std::stringstream reasonStream; |
3052 | reasonStream << "Reference of struct type " |
3053 | << field.type()->getStruct()->name().c_str() |
3054 | << " exceeds maximum allowed nesting level of " |
3055 | << kWebGLMaxStructNesting; |
3056 | std::string reason = reasonStream.str(); |
3057 | error(line, reason.c_str(), field.name().c_str(), "" ); |
3058 | return true; |
3059 | } |
3060 | |
3061 | return false; |
3062 | } |
3063 | |
3064 | TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, const TType *funcReturnType) |
3065 | { |
3066 | if(child == nullptr) |
3067 | { |
3068 | return nullptr; |
3069 | } |
3070 | |
3071 | switch(op) |
3072 | { |
3073 | case EOpLogicalNot: |
3074 | if(child->getBasicType() != EbtBool || |
3075 | child->isMatrix() || |
3076 | child->isArray() || |
3077 | child->isVector()) |
3078 | { |
3079 | return nullptr; |
3080 | } |
3081 | break; |
3082 | case EOpBitwiseNot: |
3083 | if((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || |
3084 | child->isMatrix() || |
3085 | child->isArray()) |
3086 | { |
3087 | return nullptr; |
3088 | } |
3089 | break; |
3090 | case EOpPostIncrement: |
3091 | case EOpPreIncrement: |
3092 | case EOpPostDecrement: |
3093 | case EOpPreDecrement: |
3094 | case EOpNegative: |
3095 | if(child->getBasicType() == EbtStruct || |
3096 | child->getBasicType() == EbtBool || |
3097 | child->isArray()) |
3098 | { |
3099 | return nullptr; |
3100 | } |
3101 | // Operators for built-ins are already type checked against their prototype. |
3102 | default: |
3103 | break; |
3104 | } |
3105 | |
3106 | return intermediate.addUnaryMath(op, child, loc, funcReturnType); |
3107 | } |
3108 | |
3109 | TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) |
3110 | { |
3111 | TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); |
3112 | if(node == nullptr) |
3113 | { |
3114 | unaryOpError(loc, getOperatorString(op), child->getCompleteString()); |
3115 | recover(); |
3116 | return child; |
3117 | } |
3118 | return node; |
3119 | } |
3120 | |
3121 | TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc) |
3122 | { |
3123 | if(lValueErrorCheck(loc, getOperatorString(op), child)) |
3124 | recover(); |
3125 | return addUnaryMath(op, child, loc); |
3126 | } |
3127 | |
3128 | bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) |
3129 | { |
3130 | if(left->isArray() || right->isArray()) |
3131 | { |
3132 | if(mShaderVersion < 300) |
3133 | { |
3134 | error(loc, "Invalid operation for arrays" , getOperatorString(op)); |
3135 | return false; |
3136 | } |
3137 | |
3138 | if(left->isArray() != right->isArray()) |
3139 | { |
3140 | error(loc, "array / non-array mismatch" , getOperatorString(op)); |
3141 | return false; |
3142 | } |
3143 | |
3144 | switch(op) |
3145 | { |
3146 | case EOpEqual: |
3147 | case EOpNotEqual: |
3148 | case EOpAssign: |
3149 | case EOpInitialize: |
3150 | break; |
3151 | default: |
3152 | error(loc, "Invalid operation for arrays" , getOperatorString(op)); |
3153 | return false; |
3154 | } |
3155 | // At this point, size of implicitly sized arrays should be resolved. |
3156 | if(left->getArraySize() != right->getArraySize()) |
3157 | { |
3158 | error(loc, "array size mismatch" , getOperatorString(op)); |
3159 | return false; |
3160 | } |
3161 | } |
3162 | |
3163 | // Check ops which require integer / ivec parameters |
3164 | bool isBitShift = false; |
3165 | switch(op) |
3166 | { |
3167 | case EOpBitShiftLeft: |
3168 | case EOpBitShiftRight: |
3169 | case EOpBitShiftLeftAssign: |
3170 | case EOpBitShiftRightAssign: |
3171 | // Unsigned can be bit-shifted by signed and vice versa, but we need to |
3172 | // check that the basic type is an integer type. |
3173 | isBitShift = true; |
3174 | if(!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) |
3175 | { |
3176 | return false; |
3177 | } |
3178 | break; |
3179 | case EOpBitwiseAnd: |
3180 | case EOpBitwiseXor: |
3181 | case EOpBitwiseOr: |
3182 | case EOpBitwiseAndAssign: |
3183 | case EOpBitwiseXorAssign: |
3184 | case EOpBitwiseOrAssign: |
3185 | // It is enough to check the type of only one operand, since later it |
3186 | // is checked that the operand types match. |
3187 | if(!IsInteger(left->getBasicType())) |
3188 | { |
3189 | return false; |
3190 | } |
3191 | break; |
3192 | default: |
3193 | break; |
3194 | } |
3195 | |
3196 | // GLSL ES 1.00 and 3.00 do not support implicit type casting. |
3197 | // So the basic type should usually match. |
3198 | if(!isBitShift && left->getBasicType() != right->getBasicType()) |
3199 | { |
3200 | return false; |
3201 | } |
3202 | |
3203 | // Check that type sizes match exactly on ops that require that. |
3204 | // Also check restrictions for structs that contain arrays or samplers. |
3205 | switch(op) |
3206 | { |
3207 | case EOpAssign: |
3208 | case EOpInitialize: |
3209 | case EOpEqual: |
3210 | case EOpNotEqual: |
3211 | // ESSL 1.00 sections 5.7, 5.8, 5.9 |
3212 | if(mShaderVersion < 300 && left->getType().isStructureContainingArrays()) |
3213 | { |
3214 | error(loc, "undefined operation for structs containing arrays" , getOperatorString(op)); |
3215 | return false; |
3216 | } |
3217 | // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, |
3218 | // we interpret the spec so that this extends to structs containing samplers, |
3219 | // similarly to ESSL 1.00 spec. |
3220 | if((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && |
3221 | left->getType().isStructureContainingSamplers()) |
3222 | { |
3223 | error(loc, "undefined operation for structs containing samplers" , getOperatorString(op)); |
3224 | return false; |
3225 | } |
3226 | case EOpLessThan: |
3227 | case EOpGreaterThan: |
3228 | case EOpLessThanEqual: |
3229 | case EOpGreaterThanEqual: |
3230 | if((left->getNominalSize() != right->getNominalSize()) || |
3231 | (left->getSecondarySize() != right->getSecondarySize())) |
3232 | { |
3233 | return false; |
3234 | } |
3235 | break; |
3236 | case EOpAdd: |
3237 | case EOpSub: |
3238 | case EOpDiv: |
3239 | case EOpIMod: |
3240 | case EOpBitShiftLeft: |
3241 | case EOpBitShiftRight: |
3242 | case EOpBitwiseAnd: |
3243 | case EOpBitwiseXor: |
3244 | case EOpBitwiseOr: |
3245 | case EOpAddAssign: |
3246 | case EOpSubAssign: |
3247 | case EOpDivAssign: |
3248 | case EOpIModAssign: |
3249 | case EOpBitShiftLeftAssign: |
3250 | case EOpBitShiftRightAssign: |
3251 | case EOpBitwiseAndAssign: |
3252 | case EOpBitwiseXorAssign: |
3253 | case EOpBitwiseOrAssign: |
3254 | if((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) |
3255 | { |
3256 | return false; |
3257 | } |
3258 | |
3259 | // Are the sizes compatible? |
3260 | if(left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize()) |
3261 | { |
3262 | // If the nominal sizes of operands do not match: |
3263 | // One of them must be a scalar. |
3264 | if(!left->isScalar() && !right->isScalar()) |
3265 | return false; |
3266 | |
3267 | // In the case of compound assignment other than multiply-assign, |
3268 | // the right side needs to be a scalar. Otherwise a vector/matrix |
3269 | // would be assigned to a scalar. A scalar can't be shifted by a |
3270 | // vector either. |
3271 | if(!right->isScalar() && (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) |
3272 | return false; |
3273 | } |
3274 | break; |
3275 | default: |
3276 | break; |
3277 | } |
3278 | |
3279 | return true; |
3280 | } |
3281 | |
3282 | TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc) |
3283 | { |
3284 | TBasicType switchType = init->getBasicType(); |
3285 | if((switchType != EbtInt && switchType != EbtUInt) || |
3286 | init->isMatrix() || |
3287 | init->isArray() || |
3288 | init->isVector()) |
3289 | { |
3290 | error(init->getLine(), "init-expression in a switch statement must be a scalar integer" , "switch" ); |
3291 | recover(); |
3292 | return nullptr; |
3293 | } |
3294 | |
3295 | if(statementList) |
3296 | { |
3297 | if(!ValidateSwitch::validate(switchType, this, statementList, loc)) |
3298 | { |
3299 | recover(); |
3300 | return nullptr; |
3301 | } |
3302 | } |
3303 | |
3304 | TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc); |
3305 | if(node == nullptr) |
3306 | { |
3307 | error(loc, "erroneous switch statement" , "switch" ); |
3308 | recover(); |
3309 | return nullptr; |
3310 | } |
3311 | return node; |
3312 | } |
3313 | |
3314 | TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) |
3315 | { |
3316 | if(mSwitchNestingLevel == 0) |
3317 | { |
3318 | error(loc, "case labels need to be inside switch statements" , "case" ); |
3319 | recover(); |
3320 | return nullptr; |
3321 | } |
3322 | if(condition == nullptr) |
3323 | { |
3324 | error(loc, "case label must have a condition" , "case" ); |
3325 | recover(); |
3326 | return nullptr; |
3327 | } |
3328 | if((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || |
3329 | condition->isMatrix() || |
3330 | condition->isArray() || |
3331 | condition->isVector()) |
3332 | { |
3333 | error(condition->getLine(), "case label must be a scalar integer" , "case" ); |
3334 | recover(); |
3335 | } |
3336 | TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); |
3337 | if(conditionConst == nullptr) |
3338 | { |
3339 | error(condition->getLine(), "case label must be constant" , "case" ); |
3340 | recover(); |
3341 | } |
3342 | TIntermCase *node = intermediate.addCase(condition, loc); |
3343 | if(node == nullptr) |
3344 | { |
3345 | error(loc, "erroneous case statement" , "case" ); |
3346 | recover(); |
3347 | return nullptr; |
3348 | } |
3349 | return node; |
3350 | } |
3351 | |
3352 | TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) |
3353 | { |
3354 | if(mSwitchNestingLevel == 0) |
3355 | { |
3356 | error(loc, "default labels need to be inside switch statements" , "default" ); |
3357 | recover(); |
3358 | return nullptr; |
3359 | } |
3360 | TIntermCase *node = intermediate.addCase(nullptr, loc); |
3361 | if(node == nullptr) |
3362 | { |
3363 | error(loc, "erroneous default statement" , "default" ); |
3364 | recover(); |
3365 | return nullptr; |
3366 | } |
3367 | return node; |
3368 | } |
3369 | TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) |
3370 | { |
3371 | if(binaryOpCommonCheck(op, left, right, loc)) |
3372 | { |
3373 | return intermediate.addAssign(op, left, right, loc); |
3374 | } |
3375 | return nullptr; |
3376 | } |
3377 | |
3378 | TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) |
3379 | { |
3380 | TIntermTyped *node = createAssign(op, left, right, loc); |
3381 | if(node == nullptr) |
3382 | { |
3383 | assignError(loc, "assign" , left->getCompleteString(), right->getCompleteString()); |
3384 | recover(); |
3385 | return left; |
3386 | } |
3387 | return node; |
3388 | } |
3389 | |
3390 | TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, |
3391 | const TSourceLoc &loc) |
3392 | { |
3393 | if(!binaryOpCommonCheck(op, left, right, loc)) |
3394 | return nullptr; |
3395 | |
3396 | switch(op) |
3397 | { |
3398 | case EOpEqual: |
3399 | case EOpNotEqual: |
3400 | break; |
3401 | case EOpLessThan: |
3402 | case EOpGreaterThan: |
3403 | case EOpLessThanEqual: |
3404 | case EOpGreaterThanEqual: |
3405 | ASSERT(!left->isArray() && !right->isArray()); |
3406 | if(left->isMatrix() || left->isVector() || |
3407 | left->getBasicType() == EbtStruct) |
3408 | { |
3409 | return nullptr; |
3410 | } |
3411 | break; |
3412 | case EOpLogicalOr: |
3413 | case EOpLogicalXor: |
3414 | case EOpLogicalAnd: |
3415 | ASSERT(!left->isArray() && !right->isArray()); |
3416 | if(left->getBasicType() != EbtBool || |
3417 | left->isMatrix() || left->isVector()) |
3418 | { |
3419 | return nullptr; |
3420 | } |
3421 | break; |
3422 | case EOpAdd: |
3423 | case EOpSub: |
3424 | case EOpDiv: |
3425 | case EOpMul: |
3426 | ASSERT(!left->isArray() && !right->isArray()); |
3427 | if(left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) |
3428 | { |
3429 | return nullptr; |
3430 | } |
3431 | break; |
3432 | case EOpIMod: |
3433 | ASSERT(!left->isArray() && !right->isArray()); |
3434 | // Note that this is only for the % operator, not for mod() |
3435 | if(left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) |
3436 | { |
3437 | return nullptr; |
3438 | } |
3439 | break; |
3440 | // Note that for bitwise ops, type checking is done in promote() to |
3441 | // share code between ops and compound assignment |
3442 | default: |
3443 | break; |
3444 | } |
3445 | |
3446 | return intermediate.addBinaryMath(op, left, right, loc); |
3447 | } |
3448 | |
3449 | TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) |
3450 | { |
3451 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); |
3452 | if(node == 0) |
3453 | { |
3454 | binaryOpError(loc, getOperatorString(op), left->getCompleteString(), right->getCompleteString()); |
3455 | recover(); |
3456 | return left; |
3457 | } |
3458 | return node; |
3459 | } |
3460 | |
3461 | TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) |
3462 | { |
3463 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); |
3464 | if(node == 0) |
3465 | { |
3466 | binaryOpError(loc, getOperatorString(op), left->getCompleteString(), right->getCompleteString()); |
3467 | recover(); |
3468 | ConstantUnion *unionArray = new ConstantUnion[1]; |
3469 | unionArray->setBConst(false); |
3470 | return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConstExpr), loc); |
3471 | } |
3472 | return node; |
3473 | } |
3474 | |
3475 | TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) |
3476 | { |
3477 | switch(op) |
3478 | { |
3479 | case EOpContinue: |
3480 | if(mLoopNestingLevel <= 0) |
3481 | { |
3482 | error(loc, "continue statement only allowed in loops" , "" ); |
3483 | recover(); |
3484 | } |
3485 | break; |
3486 | case EOpBreak: |
3487 | if(mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) |
3488 | { |
3489 | error(loc, "break statement only allowed in loops and switch statements" , "" ); |
3490 | recover(); |
3491 | } |
3492 | break; |
3493 | case EOpReturn: |
3494 | if(mCurrentFunctionType->getBasicType() != EbtVoid) |
3495 | { |
3496 | error(loc, "non-void function must return a value" , "return" ); |
3497 | recover(); |
3498 | } |
3499 | break; |
3500 | default: |
3501 | // No checks for discard |
3502 | break; |
3503 | } |
3504 | return intermediate.addBranch(op, loc); |
3505 | } |
3506 | |
3507 | TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc) |
3508 | { |
3509 | ASSERT(op == EOpReturn); |
3510 | mFunctionReturnsValue = true; |
3511 | if(mCurrentFunctionType->getBasicType() == EbtVoid) |
3512 | { |
3513 | error(loc, "void function cannot return a value" , "return" ); |
3514 | recover(); |
3515 | } |
3516 | else if(*mCurrentFunctionType != returnValue->getType()) |
3517 | { |
3518 | error(loc, "function return is not matching type:" , "return" ); |
3519 | recover(); |
3520 | } |
3521 | return intermediate.addBranch(op, returnValue, loc); |
3522 | } |
3523 | |
3524 | TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *paramNode, TIntermNode *thisNode, const TSourceLoc &loc, bool *fatalError) |
3525 | { |
3526 | *fatalError = false; |
3527 | TOperator op = fnCall->getBuiltInOp(); |
3528 | TIntermTyped *callNode = nullptr; |
3529 | |
3530 | if(thisNode != nullptr) |
3531 | { |
3532 | ConstantUnion *unionArray = new ConstantUnion[1]; |
3533 | int arraySize = 0; |
3534 | TIntermTyped *typedThis = thisNode->getAsTyped(); |
3535 | if(fnCall->getName() != "length" ) |
3536 | { |
3537 | error(loc, "invalid method" , fnCall->getName().c_str()); |
3538 | recover(); |
3539 | } |
3540 | else if(paramNode != nullptr) |
3541 | { |
3542 | error(loc, "method takes no parameters" , "length" ); |
3543 | recover(); |
3544 | } |
3545 | else if(typedThis == nullptr || !typedThis->isArray()) |
3546 | { |
3547 | error(loc, "length can only be called on arrays" , "length" ); |
3548 | recover(); |
3549 | } |
3550 | else |
3551 | { |
3552 | arraySize = typedThis->getArraySize(); |
3553 | } |
3554 | unionArray->setIConst(arraySize); |
3555 | callNode = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), loc); |
3556 | } |
3557 | else if(op != EOpNull) |
3558 | { |
3559 | // |
3560 | // Then this should be a constructor. |
3561 | // Don't go through the symbol table for constructors. |
3562 | // Their parameters will be verified algorithmically. |
3563 | // |
3564 | TType type(EbtVoid, EbpUndefined); // use this to get the type back |
3565 | if(!constructorErrorCheck(loc, paramNode, *fnCall, op, &type)) |
3566 | { |
3567 | // |
3568 | // It's a constructor, of type 'type'. |
3569 | // |
3570 | callNode = addConstructor(paramNode, &type, op, fnCall, loc); |
3571 | } |
3572 | |
3573 | if(callNode == nullptr) |
3574 | { |
3575 | recover(); |
3576 | callNode = intermediate.setAggregateOperator(nullptr, op, loc); |
3577 | } |
3578 | } |
3579 | else |
3580 | { |
3581 | // |
3582 | // Not a constructor. Find it in the symbol table. |
3583 | // |
3584 | const TFunction *fnCandidate; |
3585 | bool builtIn; |
3586 | fnCandidate = findFunction(loc, fnCall, &builtIn); |
3587 | if(fnCandidate) |
3588 | { |
3589 | // |
3590 | // A declared function. |
3591 | // |
3592 | if(builtIn && !fnCandidate->getExtension().empty() && |
3593 | extensionErrorCheck(loc, fnCandidate->getExtension())) |
3594 | { |
3595 | recover(); |
3596 | } |
3597 | op = fnCandidate->getBuiltInOp(); |
3598 | if(builtIn && op != EOpNull) |
3599 | { |
3600 | // |
3601 | // A function call mapped to a built-in operation. |
3602 | // |
3603 | if(fnCandidate->getParamCount() == 1) |
3604 | { |
3605 | // |
3606 | // Treat it like a built-in unary operator. |
3607 | // |
3608 | TIntermNode *operand = paramNode->getAsAggregate()->getSequence()[0]; |
3609 | callNode = createUnaryMath(op, operand->getAsTyped(), loc, &fnCandidate->getReturnType()); |
3610 | |
3611 | if(callNode == nullptr) |
3612 | { |
3613 | std::stringstream ; |
3614 | extraInfoStream << "built in unary operator function. Type: " |
3615 | << static_cast<TIntermTyped*>(paramNode)->getCompleteString(); |
3616 | std::string = extraInfoStream.str(); |
3617 | error(paramNode->getLine(), " wrong operand type" , "Internal Error" , extraInfo.c_str()); |
3618 | *fatalError = true; |
3619 | return nullptr; |
3620 | } |
3621 | } |
3622 | else |
3623 | { |
3624 | TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, op, loc); |
3625 | aggregate->setType(fnCandidate->getReturnType()); |
3626 | |
3627 | // Some built-in functions have out parameters too. |
3628 | functionCallLValueErrorCheck(fnCandidate, aggregate); |
3629 | |
3630 | callNode = aggregate; |
3631 | |
3632 | if(op == EOpClamp) |
3633 | { |
3634 | // Special case for clamp -- try to fold it as min(max(t, minVal), maxVal) |
3635 | TIntermSequence ¶meters = paramNode->getAsAggregate()->getSequence(); |
3636 | TIntermConstantUnion *valConstant = parameters[0]->getAsTyped()->getAsConstantUnion(); |
3637 | TIntermConstantUnion *minConstant = parameters[1]->getAsTyped()->getAsConstantUnion(); |
3638 | TIntermConstantUnion *maxConstant = parameters[2]->getAsTyped()->getAsConstantUnion(); |
3639 | |
3640 | if (valConstant && minConstant && maxConstant) |
3641 | { |
3642 | TIntermTyped *typedReturnNode = valConstant->fold(EOpMax, minConstant, infoSink()); |
3643 | if (typedReturnNode && typedReturnNode->getAsConstantUnion()) |
3644 | { |
3645 | typedReturnNode = maxConstant->fold(EOpMin, typedReturnNode->getAsConstantUnion(), infoSink()); |
3646 | } |
3647 | if (typedReturnNode) |
3648 | { |
3649 | callNode = typedReturnNode; |
3650 | } |
3651 | } |
3652 | } |
3653 | else |
3654 | { |
3655 | if(fnCandidate->getParamCount() == 2) |
3656 | { |
3657 | TIntermSequence ¶meters = paramNode->getAsAggregate()->getSequence(); |
3658 | TIntermTyped *left = parameters[0]->getAsTyped(); |
3659 | TIntermTyped *right = parameters[1]->getAsTyped(); |
3660 | |
3661 | TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); |
3662 | TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); |
3663 | if (leftTempConstant && rightTempConstant) |
3664 | { |
3665 | TIntermTyped *typedReturnNode = leftTempConstant->fold(op, rightTempConstant, infoSink()); |
3666 | |
3667 | if(typedReturnNode) |
3668 | { |
3669 | callNode = typedReturnNode; |
3670 | } |
3671 | } |
3672 | else if (op == EOpMax || op == EOpMin) |
3673 | { |
3674 | TIntermSymbol *leftSymbol = left->getAsSymbolNode(); |
3675 | TIntermSymbol *rightSymbol = right->getAsSymbolNode(); |
3676 | |
3677 | if (leftSymbol && rightSymbol && leftSymbol->getId() == rightSymbol->getId()) |
3678 | { |
3679 | callNode = left; |
3680 | } |
3681 | } |
3682 | } |
3683 | } |
3684 | } |
3685 | } |
3686 | else |
3687 | { |
3688 | // This is a real function call |
3689 | |
3690 | TIntermAggregate *aggregate = intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc); |
3691 | aggregate->setType(fnCandidate->getReturnType()); |
3692 | |
3693 | // this is how we know whether the given function is a builtIn function or a user defined function |
3694 | // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also |
3695 | // if builtIn == true, it's definitely a builtIn function with EOpNull |
3696 | if(!builtIn) |
3697 | aggregate->setUserDefined(); |
3698 | aggregate->setName(fnCandidate->getMangledName()); |
3699 | |
3700 | callNode = aggregate; |
3701 | |
3702 | functionCallLValueErrorCheck(fnCandidate, aggregate); |
3703 | } |
3704 | } |
3705 | else |
3706 | { |
3707 | // error message was put out by findFunction() |
3708 | // Put on a dummy node for error recovery |
3709 | ConstantUnion *unionArray = new ConstantUnion[1]; |
3710 | unionArray->setFConst(0.0f); |
3711 | callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConstExpr), loc); |
3712 | recover(); |
3713 | } |
3714 | } |
3715 | delete fnCall; |
3716 | return callNode; |
3717 | } |
3718 | |
3719 | TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &loc) |
3720 | { |
3721 | if(boolErrorCheck(loc, cond)) |
3722 | recover(); |
3723 | |
3724 | if(trueBlock->getType() != falseBlock->getType()) |
3725 | { |
3726 | binaryOpError(loc, ":" , trueBlock->getCompleteString(), falseBlock->getCompleteString()); |
3727 | recover(); |
3728 | return falseBlock; |
3729 | } |
3730 | // ESSL1 sections 5.2 and 5.7: |
3731 | // ESSL3 section 5.7: |
3732 | // Ternary operator is not among the operators allowed for structures/arrays. |
3733 | if(trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct) |
3734 | { |
3735 | error(loc, "ternary operator is not allowed for structures or arrays" , ":" ); |
3736 | recover(); |
3737 | return falseBlock; |
3738 | } |
3739 | return intermediate.addSelection(cond, trueBlock, falseBlock, loc); |
3740 | } |
3741 | |
3742 | // |
3743 | // Parse an array of strings using yyparse. |
3744 | // |
3745 | // Returns 0 for success. |
3746 | // |
3747 | int PaParseStrings(int count, const char* const string[], const int length[], |
3748 | TParseContext* context) { |
3749 | if ((count == 0) || !string) |
3750 | return 1; |
3751 | |
3752 | if (glslang_initialize(context)) |
3753 | return 1; |
3754 | |
3755 | int error = glslang_scan(count, string, length, context); |
3756 | if (!error) |
3757 | error = glslang_parse(context); |
3758 | |
3759 | glslang_finalize(context); |
3760 | |
3761 | return (error == 0) && (context->numErrors() == 0) ? 0 : 1; |
3762 | } |
3763 | |
3764 | |
3765 | |
3766 | |