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