| 1 | // |
| 2 | // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. |
| 3 | // Copyright (C) 2016 Google, Inc. |
| 4 | // |
| 5 | // All rights reserved. |
| 6 | // |
| 7 | // Redistribution and use in source and binary forms, with or without |
| 8 | // modification, are permitted provided that the following conditions |
| 9 | // are met: |
| 10 | // |
| 11 | // Redistributions of source code must retain the above copyright |
| 12 | // notice, this list of conditions and the following disclaimer. |
| 13 | // |
| 14 | // Redistributions in binary form must reproduce the above |
| 15 | // copyright notice, this list of conditions and the following |
| 16 | // disclaimer in the documentation and/or other materials provided |
| 17 | // with the distribution. |
| 18 | // |
| 19 | // Neither the name of 3Dlabs Inc. Ltd. nor the names of its |
| 20 | // contributors may be used to endorse or promote products derived |
| 21 | // from this software without specific prior written permission. |
| 22 | // |
| 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 27 | // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 32 | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| 33 | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 34 | // POSSIBILITY OF SUCH DAMAGE. |
| 35 | // |
| 36 | |
| 37 | // Implement the TParseContextBase class. |
| 38 | |
| 39 | #include <cstdarg> |
| 40 | |
| 41 | #include "ParseHelper.h" |
| 42 | |
| 43 | extern int yyparse(glslang::TParseContext*); |
| 44 | |
| 45 | namespace glslang { |
| 46 | |
| 47 | // |
| 48 | // Used to output syntax, parsing, and semantic errors. |
| 49 | // |
| 50 | |
| 51 | void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason, |
| 52 | const char* szToken, |
| 53 | const char* , |
| 54 | TPrefixType prefix, va_list args) |
| 55 | { |
| 56 | const int maxSize = MaxTokenLength + 200; |
| 57 | char [maxSize]; |
| 58 | |
| 59 | safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); |
| 60 | |
| 61 | infoSink.info.prefix(prefix); |
| 62 | infoSink.info.location(loc); |
| 63 | infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n" ; |
| 64 | |
| 65 | if (prefix == EPrefixError) { |
| 66 | ++numErrors; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken, |
| 71 | const char* , ...) |
| 72 | { |
| 73 | if (messages & EShMsgOnlyPreprocessor) |
| 74 | return; |
| 75 | va_list args; |
| 76 | va_start(args, szExtraInfoFormat); |
| 77 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
| 78 | va_end(args); |
| 79 | |
| 80 | if ((messages & EShMsgCascadingErrors) == 0) |
| 81 | currentScanner->setEndOfInput(); |
| 82 | } |
| 83 | |
| 84 | void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
| 85 | const char* , ...) |
| 86 | { |
| 87 | if (suppressWarnings()) |
| 88 | return; |
| 89 | va_list args; |
| 90 | va_start(args, szExtraInfoFormat); |
| 91 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
| 92 | va_end(args); |
| 93 | } |
| 94 | |
| 95 | void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, |
| 96 | const char* , ...) |
| 97 | { |
| 98 | va_list args; |
| 99 | va_start(args, szExtraInfoFormat); |
| 100 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
| 101 | va_end(args); |
| 102 | |
| 103 | if ((messages & EShMsgCascadingErrors) == 0) |
| 104 | currentScanner->setEndOfInput(); |
| 105 | } |
| 106 | |
| 107 | void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
| 108 | const char* , ...) |
| 109 | { |
| 110 | va_list args; |
| 111 | va_start(args, szExtraInfoFormat); |
| 112 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
| 113 | va_end(args); |
| 114 | } |
| 115 | |
| 116 | // |
| 117 | // Both test and if necessary, spit out an error, to see if the node is really |
| 118 | // an l-value that can be operated on this way. |
| 119 | // |
| 120 | // Returns true if there was an error. |
| 121 | // |
| 122 | bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) |
| 123 | { |
| 124 | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
| 125 | |
| 126 | if (binaryNode) { |
| 127 | switch(binaryNode->getOp()) { |
| 128 | case EOpIndexDirect: |
| 129 | case EOpIndexIndirect: // fall through |
| 130 | case EOpIndexDirectStruct: // fall through |
| 131 | case EOpVectorSwizzle: |
| 132 | case EOpMatrixSwizzle: |
| 133 | return lValueErrorCheck(loc, op, binaryNode->getLeft()); |
| 134 | default: |
| 135 | break; |
| 136 | } |
| 137 | error(loc, " l-value required" , op, "" , "" ); |
| 138 | |
| 139 | return true; |
| 140 | } |
| 141 | |
| 142 | const char* symbol = nullptr; |
| 143 | TIntermSymbol* symNode = node->getAsSymbolNode(); |
| 144 | if (symNode != nullptr) |
| 145 | symbol = symNode->getName().c_str(); |
| 146 | |
| 147 | const char* message = nullptr; |
| 148 | switch (node->getQualifier().storage) { |
| 149 | case EvqConst: message = "can't modify a const" ; break; |
| 150 | case EvqConstReadOnly: message = "can't modify a const" ; break; |
| 151 | case EvqUniform: message = "can't modify a uniform" ; break; |
| 152 | case EvqBuffer: |
| 153 | if (node->getQualifier().readonly) |
| 154 | message = "can't modify a readonly buffer" ; |
| 155 | #ifdef NV_EXTENSIONS |
| 156 | if (node->getQualifier().layoutShaderRecordNV) |
| 157 | message = "can't modify a shaderrecordnv qualified buffer" ; |
| 158 | #endif |
| 159 | break; |
| 160 | #ifdef NV_EXTENSIONS |
| 161 | case EvqHitAttrNV: |
| 162 | if (language != EShLangIntersectNV) |
| 163 | message = "cannot modify hitAttributeNV in this stage" ; |
| 164 | break; |
| 165 | #endif |
| 166 | |
| 167 | default: |
| 168 | // |
| 169 | // Type that can't be written to? |
| 170 | // |
| 171 | switch (node->getBasicType()) { |
| 172 | case EbtSampler: |
| 173 | message = "can't modify a sampler" ; |
| 174 | break; |
| 175 | case EbtAtomicUint: |
| 176 | message = "can't modify an atomic_uint" ; |
| 177 | break; |
| 178 | case EbtVoid: |
| 179 | message = "can't modify void" ; |
| 180 | break; |
| 181 | #ifdef NV_EXTENSIONS |
| 182 | case EbtAccStructNV: |
| 183 | message = "can't modify accelerationStructureNV" ; |
| 184 | break; |
| 185 | #endif |
| 186 | default: |
| 187 | break; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | if (message == nullptr && binaryNode == nullptr && symNode == nullptr) { |
| 192 | error(loc, " l-value required" , op, "" , "" ); |
| 193 | |
| 194 | return true; |
| 195 | } |
| 196 | |
| 197 | // |
| 198 | // Everything else is okay, no error. |
| 199 | // |
| 200 | if (message == nullptr) |
| 201 | return false; |
| 202 | |
| 203 | // |
| 204 | // If we get here, we have an error and a message. |
| 205 | // |
| 206 | if (symNode) |
| 207 | error(loc, " l-value required" , op, "\"%s\" (%s)" , symbol, message); |
| 208 | else |
| 209 | error(loc, " l-value required" , op, "(%s)" , message); |
| 210 | |
| 211 | return true; |
| 212 | } |
| 213 | |
| 214 | // Test for and give an error if the node can't be read from. |
| 215 | void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) |
| 216 | { |
| 217 | if (! node) |
| 218 | return; |
| 219 | |
| 220 | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
| 221 | if (binaryNode) { |
| 222 | switch(binaryNode->getOp()) { |
| 223 | case EOpIndexDirect: |
| 224 | case EOpIndexIndirect: |
| 225 | case EOpIndexDirectStruct: |
| 226 | case EOpVectorSwizzle: |
| 227 | case EOpMatrixSwizzle: |
| 228 | rValueErrorCheck(loc, op, binaryNode->getLeft()); |
| 229 | default: |
| 230 | break; |
| 231 | } |
| 232 | |
| 233 | return; |
| 234 | } |
| 235 | |
| 236 | TIntermSymbol* symNode = node->getAsSymbolNode(); |
| 237 | if (symNode && symNode->getQualifier().writeonly) |
| 238 | error(loc, "can't read from writeonly object: " , op, symNode->getName().c_str()); |
| 239 | } |
| 240 | |
| 241 | // Add 'symbol' to the list of deferred linkage symbols, which |
| 242 | // are later processed in finish(), at which point the symbol |
| 243 | // must still be valid. |
| 244 | // It is okay if the symbol's type will be subsequently edited; |
| 245 | // the modifications will be tracked. |
| 246 | // Order is preserved, to avoid creating novel forward references. |
| 247 | void TParseContextBase::trackLinkage(TSymbol& symbol) |
| 248 | { |
| 249 | if (!parsingBuiltins) |
| 250 | linkageSymbols.push_back(&symbol); |
| 251 | } |
| 252 | |
| 253 | // Ensure index is in bounds, correct if necessary. |
| 254 | // Give an error if not. |
| 255 | void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int& index) |
| 256 | { |
| 257 | if (index < 0) { |
| 258 | error(loc, "" , "[" , "index out of range '%d'" , index); |
| 259 | index = 0; |
| 260 | } else if (type.isArray()) { |
| 261 | if (type.isSizedArray() && index >= type.getOuterArraySize()) { |
| 262 | error(loc, "" , "[" , "array index out of range '%d'" , index); |
| 263 | index = type.getOuterArraySize() - 1; |
| 264 | } |
| 265 | } else if (type.isVector()) { |
| 266 | if (index >= type.getVectorSize()) { |
| 267 | error(loc, "" , "[" , "vector index out of range '%d'" , index); |
| 268 | index = type.getVectorSize() - 1; |
| 269 | } |
| 270 | } else if (type.isMatrix()) { |
| 271 | if (index >= type.getMatrixCols()) { |
| 272 | error(loc, "" , "[" , "matrix index out of range '%d'" , index); |
| 273 | index = type.getMatrixCols() - 1; |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | // Make a shared symbol have a non-shared version that can be edited by the current |
| 279 | // compile, such that editing its type will not change the shared version and will |
| 280 | // effect all nodes already sharing it (non-shallow type), |
| 281 | // or adopting its full type after being edited (shallow type). |
| 282 | void TParseContextBase::makeEditable(TSymbol*& symbol) |
| 283 | { |
| 284 | // copyUp() does a deep copy of the type. |
| 285 | symbol = symbolTable.copyUp(symbol); |
| 286 | |
| 287 | // Save it (deferred, so it can be edited first) in the AST for linker use. |
| 288 | if (symbol) |
| 289 | trackLinkage(*symbol); |
| 290 | } |
| 291 | |
| 292 | // Return a writable version of the variable 'name'. |
| 293 | // |
| 294 | // Return nullptr if 'name' is not found. This should mean |
| 295 | // something is seriously wrong (e.g., compiler asking self for |
| 296 | // built-in that doesn't exist). |
| 297 | TVariable* TParseContextBase::getEditableVariable(const char* name) |
| 298 | { |
| 299 | bool builtIn; |
| 300 | TSymbol* symbol = symbolTable.find(name, &builtIn); |
| 301 | |
| 302 | assert(symbol != nullptr); |
| 303 | if (symbol == nullptr) |
| 304 | return nullptr; |
| 305 | |
| 306 | if (builtIn) |
| 307 | makeEditable(symbol); |
| 308 | |
| 309 | return symbol->getAsVariable(); |
| 310 | } |
| 311 | |
| 312 | // Select the best matching function for 'call' from 'candidateList'. |
| 313 | // |
| 314 | // Assumptions |
| 315 | // |
| 316 | // There is no exact match, so a selection algorithm needs to run. That is, the |
| 317 | // language-specific handler should check for exact match first, to |
| 318 | // decide what to do, before calling this selector. |
| 319 | // |
| 320 | // Input |
| 321 | // |
| 322 | // * list of candidate signatures to select from |
| 323 | // * the call |
| 324 | // * a predicate function convertible(from, to) that says whether or not type |
| 325 | // 'from' can implicitly convert to type 'to' (it includes the case of what |
| 326 | // the calling language would consider a matching type with no conversion |
| 327 | // needed) |
| 328 | // * a predicate function better(from1, from2, to1, to2) that says whether or |
| 329 | // not a conversion from <-> to2 is considered better than a conversion |
| 330 | // from <-> to1 (both in and out directions need testing, as declared by the |
| 331 | // formal parameter) |
| 332 | // |
| 333 | // Output |
| 334 | // |
| 335 | // * best matching candidate (or none, if no viable candidates found) |
| 336 | // * whether there was a tie for the best match (ambiguous overload selection, |
| 337 | // caller's choice for how to report) |
| 338 | // |
| 339 | const TFunction* TParseContextBase::selectFunction( |
| 340 | const TVector<const TFunction*> candidateList, |
| 341 | const TFunction& call, |
| 342 | std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible, |
| 343 | std::function<bool(const TType& from, const TType& to1, const TType& to2)> better, |
| 344 | /* output */ bool& tie) |
| 345 | { |
| 346 | // |
| 347 | // Operation |
| 348 | // |
| 349 | // 1. Prune the input list of candidates down to a list of viable candidates, |
| 350 | // where each viable candidate has |
| 351 | // |
| 352 | // * at least as many parameters as there are calling arguments, with any |
| 353 | // remaining parameters being optional or having default values |
| 354 | // * each parameter is true under convertible(A, B), where A is the calling |
| 355 | // type for in and B is the formal type, and in addition, for out B is the |
| 356 | // calling type and A is the formal type |
| 357 | // |
| 358 | // 2. If there are no viable candidates, return with no match. |
| 359 | // |
| 360 | // 3. If there is only one viable candidate, it is the best match. |
| 361 | // |
| 362 | // 4. If there are multiple viable candidates, select the first viable candidate |
| 363 | // as the incumbent. Compare the incumbent to the next viable candidate, and if |
| 364 | // that candidate is better (bullets below), make it the incumbent. Repeat, with |
| 365 | // a linear walk through the viable candidate list. The final incumbent will be |
| 366 | // returned as the best match. A viable candidate is better than the incumbent if |
| 367 | // |
| 368 | // * it has a function argument with a better(...) conversion than the incumbent, |
| 369 | // for all directions needed by in and out |
| 370 | // * the incumbent has no argument with a better(...) conversion then the |
| 371 | // candidate, for either in or out (as needed) |
| 372 | // |
| 373 | // 5. Check for ambiguity by comparing the best match against all other viable |
| 374 | // candidates. If any other viable candidate has a function argument with a |
| 375 | // better(...) conversion than the best candidate (for either in or out |
| 376 | // directions), return that there was a tie for best. |
| 377 | // |
| 378 | |
| 379 | tie = false; |
| 380 | |
| 381 | // 1. prune to viable... |
| 382 | TVector<const TFunction*> viableCandidates; |
| 383 | for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { |
| 384 | const TFunction& candidate = *(*it); |
| 385 | |
| 386 | // to even be a potential match, number of arguments must be >= the number of |
| 387 | // fixed (non-default) parameters, and <= the total (including parameter with defaults). |
| 388 | if (call.getParamCount() < candidate.getFixedParamCount() || |
| 389 | call.getParamCount() > candidate.getParamCount()) |
| 390 | continue; |
| 391 | |
| 392 | // see if arguments are convertible |
| 393 | bool viable = true; |
| 394 | |
| 395 | // The call can have fewer parameters than the candidate, if some have defaults. |
| 396 | const int paramCount = std::min(call.getParamCount(), candidate.getParamCount()); |
| 397 | for (int param = 0; param < paramCount; ++param) { |
| 398 | if (candidate[param].type->getQualifier().isParamInput()) { |
| 399 | if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) { |
| 400 | viable = false; |
| 401 | break; |
| 402 | } |
| 403 | } |
| 404 | if (candidate[param].type->getQualifier().isParamOutput()) { |
| 405 | if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) { |
| 406 | viable = false; |
| 407 | break; |
| 408 | } |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | if (viable) |
| 413 | viableCandidates.push_back(&candidate); |
| 414 | } |
| 415 | |
| 416 | // 2. none viable... |
| 417 | if (viableCandidates.size() == 0) |
| 418 | return nullptr; |
| 419 | |
| 420 | // 3. only one viable... |
| 421 | if (viableCandidates.size() == 1) |
| 422 | return viableCandidates.front(); |
| 423 | |
| 424 | // 4. find best... |
| 425 | const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
| 426 | // is call -> can2 better than call -> can1 for any parameter |
| 427 | bool hasBetterParam = false; |
| 428 | for (int param = 0; param < call.getParamCount(); ++param) { |
| 429 | if (better(*call[param].type, *can1[param].type, *can2[param].type)) { |
| 430 | hasBetterParam = true; |
| 431 | break; |
| 432 | } |
| 433 | } |
| 434 | return hasBetterParam; |
| 435 | }; |
| 436 | |
| 437 | const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
| 438 | // is call -> can2 equivalent to call -> can1 for all the call parameters? |
| 439 | for (int param = 0; param < call.getParamCount(); ++param) { |
| 440 | if (better(*call[param].type, *can1[param].type, *can2[param].type) || |
| 441 | better(*call[param].type, *can2[param].type, *can1[param].type)) |
| 442 | return false; |
| 443 | } |
| 444 | return true; |
| 445 | }; |
| 446 | |
| 447 | const TFunction* incumbent = viableCandidates.front(); |
| 448 | for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) { |
| 449 | const TFunction& candidate = *(*it); |
| 450 | if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent)) |
| 451 | incumbent = &candidate; |
| 452 | } |
| 453 | |
| 454 | // 5. ambiguity... |
| 455 | for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) { |
| 456 | if (incumbent == *it) |
| 457 | continue; |
| 458 | const TFunction& candidate = *(*it); |
| 459 | |
| 460 | // In the case of default parameters, it may have an identical initial set, which is |
| 461 | // also ambiguous |
| 462 | if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate)) |
| 463 | tie = true; |
| 464 | } |
| 465 | |
| 466 | return incumbent; |
| 467 | } |
| 468 | |
| 469 | // |
| 470 | // Look at a '.' field selector string and change it into numerical selectors |
| 471 | // for a vector or scalar. |
| 472 | // |
| 473 | // Always return some form of swizzle, so the result is always usable. |
| 474 | // |
| 475 | void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize, |
| 476 | TSwizzleSelectors<TVectorSelector>& selector) |
| 477 | { |
| 478 | // Too long? |
| 479 | if (compString.size() > MaxSwizzleSelectors) |
| 480 | error(loc, "vector swizzle too long" , compString.c_str(), "" ); |
| 481 | |
| 482 | // Use this to test that all swizzle characters are from the same swizzle-namespace-set |
| 483 | enum { |
| 484 | exyzw, |
| 485 | ergba, |
| 486 | estpq, |
| 487 | } fieldSet[MaxSwizzleSelectors]; |
| 488 | |
| 489 | // Decode the swizzle string. |
| 490 | int size = std::min(MaxSwizzleSelectors, (int)compString.size()); |
| 491 | for (int i = 0; i < size; ++i) { |
| 492 | switch (compString[i]) { |
| 493 | case 'x': |
| 494 | selector.push_back(0); |
| 495 | fieldSet[i] = exyzw; |
| 496 | break; |
| 497 | case 'r': |
| 498 | selector.push_back(0); |
| 499 | fieldSet[i] = ergba; |
| 500 | break; |
| 501 | case 's': |
| 502 | selector.push_back(0); |
| 503 | fieldSet[i] = estpq; |
| 504 | break; |
| 505 | |
| 506 | case 'y': |
| 507 | selector.push_back(1); |
| 508 | fieldSet[i] = exyzw; |
| 509 | break; |
| 510 | case 'g': |
| 511 | selector.push_back(1); |
| 512 | fieldSet[i] = ergba; |
| 513 | break; |
| 514 | case 't': |
| 515 | selector.push_back(1); |
| 516 | fieldSet[i] = estpq; |
| 517 | break; |
| 518 | |
| 519 | case 'z': |
| 520 | selector.push_back(2); |
| 521 | fieldSet[i] = exyzw; |
| 522 | break; |
| 523 | case 'b': |
| 524 | selector.push_back(2); |
| 525 | fieldSet[i] = ergba; |
| 526 | break; |
| 527 | case 'p': |
| 528 | selector.push_back(2); |
| 529 | fieldSet[i] = estpq; |
| 530 | break; |
| 531 | |
| 532 | case 'w': |
| 533 | selector.push_back(3); |
| 534 | fieldSet[i] = exyzw; |
| 535 | break; |
| 536 | case 'a': |
| 537 | selector.push_back(3); |
| 538 | fieldSet[i] = ergba; |
| 539 | break; |
| 540 | case 'q': |
| 541 | selector.push_back(3); |
| 542 | fieldSet[i] = estpq; |
| 543 | break; |
| 544 | |
| 545 | default: |
| 546 | error(loc, "unknown swizzle selection" , compString.c_str(), "" ); |
| 547 | break; |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | // Additional error checking. |
| 552 | for (int i = 0; i < selector.size(); ++i) { |
| 553 | if (selector[i] >= vecSize) { |
| 554 | error(loc, "vector swizzle selection out of range" , compString.c_str(), "" ); |
| 555 | selector.resize(i); |
| 556 | break; |
| 557 | } |
| 558 | |
| 559 | if (i > 0 && fieldSet[i] != fieldSet[i-1]) { |
| 560 | error(loc, "vector swizzle selectors not from the same set" , compString.c_str(), "" ); |
| 561 | selector.resize(i); |
| 562 | break; |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | // Ensure it is valid. |
| 567 | if (selector.size() == 0) |
| 568 | selector.push_back(0); |
| 569 | } |
| 570 | |
| 571 | // |
| 572 | // Make the passed-in variable information become a member of the |
| 573 | // global uniform block. If this doesn't exist yet, make it. |
| 574 | // |
| 575 | void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) |
| 576 | { |
| 577 | // Make the global block, if not yet made. |
| 578 | if (globalUniformBlock == nullptr) { |
| 579 | TQualifier blockQualifier; |
| 580 | blockQualifier.clear(); |
| 581 | blockQualifier.storage = EvqUniform; |
| 582 | TType blockType(new TTypeList, *NewPoolTString(getGlobalUniformBlockName()), blockQualifier); |
| 583 | setUniformBlockDefaults(blockType); |
| 584 | globalUniformBlock = new TVariable(NewPoolTString("" ), blockType, true); |
| 585 | firstNewMember = 0; |
| 586 | } |
| 587 | |
| 588 | // Update with binding and set |
| 589 | globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding; |
| 590 | globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet; |
| 591 | |
| 592 | // Add the requested member as a member to the global block. |
| 593 | TType* type = new TType; |
| 594 | type->shallowCopy(memberType); |
| 595 | type->setFieldName(memberName); |
| 596 | if (typeList) |
| 597 | type->setStruct(typeList); |
| 598 | TTypeLoc typeLoc = {type, loc}; |
| 599 | globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc); |
| 600 | |
| 601 | // Insert into the symbol table. |
| 602 | if (firstNewMember == 0) { |
| 603 | // This is the first request; we need a normal symbol table insert |
| 604 | if (symbolTable.insert(*globalUniformBlock)) |
| 605 | trackLinkage(*globalUniformBlock); |
| 606 | else |
| 607 | error(loc, "failed to insert the global constant buffer" , "uniform" , "" ); |
| 608 | } else { |
| 609 | // This is a follow-on request; we need to amend the first insert |
| 610 | symbolTable.amend(*globalUniformBlock, firstNewMember); |
| 611 | } |
| 612 | |
| 613 | ++firstNewMember; |
| 614 | } |
| 615 | |
| 616 | void TParseContextBase::finish() |
| 617 | { |
| 618 | if (parsingBuiltins) |
| 619 | return; |
| 620 | |
| 621 | // Transfer the linkage symbols to AST nodes, preserving order. |
| 622 | TIntermAggregate* linkage = new TIntermAggregate; |
| 623 | for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i) |
| 624 | intermediate.addSymbolLinkageNode(linkage, **i); |
| 625 | intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable); |
| 626 | } |
| 627 | |
| 628 | } // end namespace glslang |
| 629 | |