• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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