• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2016-2018 Google, Inc.
3 // Copyright (C) 2016 LunarG, 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 Google, Inc., 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 //
38 // This is a set of mutually recursive methods implementing the HLSL grammar.
39 // Generally, each returns
40 //  - through an argument: a type specifically appropriate to which rule it
41 //    recognized
42 //  - through the return value: true/false to indicate whether or not it
43 //    recognized its rule
44 //
45 // As much as possible, only grammar recognition should happen in this file,
46 // with all other work being farmed out to hlslParseHelper.cpp, which in turn
47 // will build the AST.
48 //
49 // The next token, yet to be "accepted" is always sitting in 'token'.
50 // When a method says it accepts a rule, that means all tokens involved
51 // in the rule will have been consumed, and none left in 'token'.
52 //
53 
54 #include "hlslTokens.h"
55 #include "hlslGrammar.h"
56 #include "hlslAttributes.h"
57 
58 namespace glslang {
59 
60 // Root entry point to this recursive decent parser.
61 // Return true if compilation unit was successfully accepted.
parse()62 bool HlslGrammar::parse()
63 {
64     advanceToken();
65     return acceptCompilationUnit();
66 }
67 
expected(const char * syntax)68 void HlslGrammar::expected(const char* syntax)
69 {
70     parseContext.error(token.loc, "Expected", syntax, "");
71 }
72 
unimplemented(const char * error)73 void HlslGrammar::unimplemented(const char* error)
74 {
75     parseContext.error(token.loc, "Unimplemented", error, "");
76 }
77 
78 // IDENTIFIER
79 // THIS
80 // type that can be used as IDENTIFIER
81 //
82 // Only process the next token if it is an identifier.
83 // Return true if it was an identifier.
acceptIdentifier(HlslToken & idToken)84 bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
85 {
86     // IDENTIFIER
87     if (peekTokenClass(EHTokIdentifier)) {
88         idToken = token;
89         advanceToken();
90         return true;
91     }
92 
93     // THIS
94     // -> maps to the IDENTIFIER spelled with the internal special name for 'this'
95     if (peekTokenClass(EHTokThis)) {
96         idToken = token;
97         advanceToken();
98         idToken.tokenClass = EHTokIdentifier;
99         idToken.string = NewPoolTString(intermediate.implicitThisName);
100         return true;
101     }
102 
103     // type that can be used as IDENTIFIER
104 
105     // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
106     // they ARE still accepted as identifiers.  This is not a dense space: e.g, "void" is not a
107     // valid identifier, nor is "linear".  This code special cases the known instances of this, so
108     // e.g, "int sample;" or "float float;" is accepted.  Other cases can be added here if needed.
109 
110     const char* idString = getTypeString(peek());
111     if (idString == nullptr)
112         return false;
113 
114     token.string     = NewPoolTString(idString);
115     token.tokenClass = EHTokIdentifier;
116     idToken = token;
117     typeIdentifiers = true;
118 
119     advanceToken();
120 
121     return true;
122 }
123 
124 // compilationUnit
125 //      : declaration_list EOF
126 //
acceptCompilationUnit()127 bool HlslGrammar::acceptCompilationUnit()
128 {
129     if (! acceptDeclarationList(unitNode))
130         return false;
131 
132     if (! peekTokenClass(EHTokNone))
133         return false;
134 
135     // set root of AST
136     if (unitNode && !unitNode->getAsAggregate())
137         unitNode = intermediate.growAggregate(nullptr, unitNode);
138     intermediate.setTreeRoot(unitNode);
139 
140     return true;
141 }
142 
143 // Recognize the following, but with the extra condition that it can be
144 // successfully terminated by EOF or '}'.
145 //
146 // declaration_list
147 //      : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
148 //
149 // declaration_or_semicolon
150 //      : declaration
151 //      : SEMICOLON
152 //
acceptDeclarationList(TIntermNode * & nodeList)153 bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
154 {
155     do {
156         // HLSL allows extra semicolons between global declarations
157         do { } while (acceptTokenClass(EHTokSemicolon));
158 
159         // EOF or RIGHT_BRACE
160         if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
161             return true;
162 
163         // declaration
164         if (! acceptDeclaration(nodeList))
165             return false;
166     } while (true);
167 
168     return true;
169 }
170 
171 // sampler_state
172 //      : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
173 //
174 // sampler_state_assignment
175 //     : sampler_state_identifier EQUAL value SEMICOLON
176 //
177 // sampler_state_identifier
178 //     : ADDRESSU
179 //     | ADDRESSV
180 //     | ADDRESSW
181 //     | BORDERCOLOR
182 //     | FILTER
183 //     | MAXANISOTROPY
184 //     | MAXLOD
185 //     | MINLOD
186 //     | MIPLODBIAS
187 //
acceptSamplerState()188 bool HlslGrammar::acceptSamplerState()
189 {
190     // TODO: this should be genericized to accept a list of valid tokens and
191     // return token/value pairs.  Presently it is specific to texture values.
192 
193     if (! acceptTokenClass(EHTokLeftBrace))
194         return true;
195 
196     parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
197 
198     do {
199         // read state name
200         HlslToken state;
201         if (! acceptIdentifier(state))
202             break;  // end of list
203 
204         // FXC accepts any case
205         TString stateName = *state.string;
206         std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
207 
208         if (! acceptTokenClass(EHTokAssign)) {
209             expected("assign");
210             return false;
211         }
212 
213         if (stateName == "minlod" || stateName == "maxlod") {
214             if (! peekTokenClass(EHTokIntConstant)) {
215                 expected("integer");
216                 return false;
217             }
218 
219             TIntermTyped* lod = nullptr;
220             if (! acceptLiteral(lod))  // should never fail, since we just looked for an integer
221                 return false;
222         } else if (stateName == "maxanisotropy") {
223             if (! peekTokenClass(EHTokIntConstant)) {
224                 expected("integer");
225                 return false;
226             }
227 
228             TIntermTyped* maxAnisotropy = nullptr;
229             if (! acceptLiteral(maxAnisotropy))  // should never fail, since we just looked for an integer
230                 return false;
231         } else if (stateName == "filter") {
232             HlslToken filterMode;
233             if (! acceptIdentifier(filterMode)) {
234                 expected("filter mode");
235                 return false;
236             }
237         } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
238             HlslToken addrMode;
239             if (! acceptIdentifier(addrMode)) {
240                 expected("texture address mode");
241                 return false;
242             }
243         } else if (stateName == "miplodbias") {
244             TIntermTyped* lodBias = nullptr;
245             if (! acceptLiteral(lodBias)) {
246                 expected("lod bias");
247                 return false;
248             }
249         } else if (stateName == "bordercolor") {
250             return false;
251         } else {
252             expected("texture state");
253             return false;
254         }
255 
256         // SEMICOLON
257         if (! acceptTokenClass(EHTokSemicolon)) {
258             expected("semicolon");
259             return false;
260         }
261     } while (true);
262 
263     if (! acceptTokenClass(EHTokRightBrace))
264         return false;
265 
266     return true;
267 }
268 
269 // sampler_declaration_dx9
270 //    : SAMPLER identifier EQUAL sampler_type sampler_state
271 //
acceptSamplerDeclarationDX9(TType &)272 bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
273 {
274     if (! acceptTokenClass(EHTokSampler))
275         return false;
276 
277     // TODO: remove this when DX9 style declarations are implemented.
278     unimplemented("Direct3D 9 sampler declaration");
279 
280     // read sampler name
281     HlslToken name;
282     if (! acceptIdentifier(name)) {
283         expected("sampler name");
284         return false;
285     }
286 
287     if (! acceptTokenClass(EHTokAssign)) {
288         expected("=");
289         return false;
290     }
291 
292     return false;
293 }
294 
295 // declaration
296 //      : attributes attributed_declaration
297 //      | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
298 //
299 // attributed_declaration
300 //      : sampler_declaration_dx9 post_decls SEMICOLON
301 //      | fully_specified_type                           // for cbuffer/tbuffer
302 //      | fully_specified_type declarator_list SEMICOLON // for non cbuffer/tbuffer
303 //      | fully_specified_type identifier function_parameters post_decls compound_statement  // function definition
304 //      | fully_specified_type identifier sampler_state post_decls compound_statement        // sampler definition
305 //      | typedef declaration
306 //
307 // declarator_list
308 //      : declarator COMMA declarator COMMA declarator...  // zero or more declarators
309 //
310 // declarator
311 //      : identifier array_specifier post_decls
312 //      | identifier array_specifier post_decls EQUAL assignment_expression
313 //      | identifier function_parameters post_decls                                          // function prototype
314 //
315 // Parsing has to go pretty far in to know whether it's a variable, prototype, or
316 // function definition, so the implementation below doesn't perfectly divide up the grammar
317 // as above.  (The 'identifier' in the first item in init_declarator list is the
318 // same as 'identifier' for function declarations.)
319 //
320 // This can generate more than one subtree, one per initializer or a function body.
321 // All initializer subtrees are put in their own aggregate node, making one top-level
322 // node for all the initializers. Each function created is a top-level node to grow
323 // into the passed-in nodeList.
324 //
325 // If 'nodeList' is passed in as non-null, it must be an aggregate to extend for
326 // each top-level node the declaration creates. Otherwise, if only one top-level
327 // node in generated here, that is want is returned in nodeList.
328 //
acceptDeclaration(TIntermNode * & nodeList)329 bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
330 {
331     // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
332     if (acceptTokenClass(EHTokNamespace)) {
333         HlslToken namespaceToken;
334         if (!acceptIdentifier(namespaceToken)) {
335             expected("namespace name");
336             return false;
337         }
338         parseContext.pushNamespace(*namespaceToken.string);
339         if (!acceptTokenClass(EHTokLeftBrace)) {
340             expected("{");
341             return false;
342         }
343         if (!acceptDeclarationList(nodeList)) {
344             expected("declaration list");
345             return false;
346         }
347         if (!acceptTokenClass(EHTokRightBrace)) {
348             expected("}");
349             return false;
350         }
351         parseContext.popNamespace();
352         return true;
353     }
354 
355     bool declarator_list = false; // true when processing comma separation
356 
357     // attributes
358     TFunctionDeclarator declarator;
359     acceptAttributes(declarator.attributes);
360 
361     // typedef
362     bool typedefDecl = acceptTokenClass(EHTokTypedef);
363 
364     TType declaredType;
365 
366     // DX9 sampler declaration use a different syntax
367     // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
368     // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
369     // HLSL shaders, this will have to be a master level switch
370     // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
371     // For that reason, this line is commented out
372     // if (acceptSamplerDeclarationDX9(declaredType))
373     //     return true;
374 
375     bool forbidDeclarators = (peekTokenClass(EHTokCBuffer) || peekTokenClass(EHTokTBuffer));
376     // fully_specified_type
377     if (! acceptFullySpecifiedType(declaredType, nodeList, declarator.attributes, forbidDeclarators))
378         return false;
379 
380     // cbuffer and tbuffer end with the closing '}'.
381     // No semicolon is included.
382     if (forbidDeclarators)
383         return true;
384 
385     // declarator_list
386     //    : declarator
387     //         : identifier
388     HlslToken idToken;
389     TIntermAggregate* initializers = nullptr;
390     while (acceptIdentifier(idToken)) {
391         TString *fullName = idToken.string;
392         if (parseContext.symbolTable.atGlobalLevel())
393             parseContext.getFullNamespaceName(fullName);
394         if (peekTokenClass(EHTokLeftParen)) {
395             // looks like function parameters
396 
397             // merge in the attributes into the return type
398             parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true);
399 
400             // Potentially rename shader entry point function.  No-op most of the time.
401             parseContext.renameShaderFunction(fullName);
402 
403             // function_parameters
404             declarator.function = new TFunction(fullName, declaredType);
405             if (!acceptFunctionParameters(*declarator.function)) {
406                 expected("function parameter list");
407                 return false;
408             }
409 
410             // post_decls
411             acceptPostDecls(declarator.function->getWritableType().getQualifier());
412 
413             // compound_statement (function body definition) or just a prototype?
414             declarator.loc = token.loc;
415             if (peekTokenClass(EHTokLeftBrace)) {
416                 if (declarator_list)
417                     parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
418                 if (typedefDecl)
419                     parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
420                 return acceptFunctionDefinition(declarator, nodeList, nullptr);
421             } else {
422                 if (typedefDecl)
423                     parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
424                 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
425             }
426         } else {
427             // A variable declaration.
428 
429             // merge in the attributes, the first time around, into the shared type
430             if (! declarator_list)
431                 parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType);
432 
433             // Fix the storage qualifier if it's a global.
434             if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
435                 declaredType.getQualifier().storage = EvqUniform;
436 
437             // recognize array_specifier
438             TArraySizes* arraySizes = nullptr;
439             acceptArraySpecifier(arraySizes);
440 
441             // We can handle multiple variables per type declaration, so
442             // the number of types can expand when arrayness is different.
443             TType variableType;
444             variableType.shallowCopy(declaredType);
445 
446             // In the most general case, arrayness is potentially coming both from the
447             // declared type and from the variable: "int[] a[];" or just one or the other.
448             // Merge it all to the variableType, so all arrayness is part of the variableType.
449             variableType.transferArraySizes(arraySizes);
450             variableType.copyArrayInnerSizes(declaredType.getArraySizes());
451 
452             // samplers accept immediate sampler state
453             if (variableType.getBasicType() == EbtSampler) {
454                 if (! acceptSamplerState())
455                     return false;
456             }
457 
458             // post_decls
459             acceptPostDecls(variableType.getQualifier());
460 
461             // EQUAL assignment_expression
462             TIntermTyped* expressionNode = nullptr;
463             if (acceptTokenClass(EHTokAssign)) {
464                 if (typedefDecl)
465                     parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
466                 if (! acceptAssignmentExpression(expressionNode)) {
467                     expected("initializer");
468                     return false;
469                 }
470             }
471 
472             // TODO: things scoped within an annotation need their own name space;
473             // TODO: strings are not yet handled.
474             if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
475                 if (typedefDecl)
476                     parseContext.declareTypedef(idToken.loc, *fullName, variableType);
477                 else if (variableType.getBasicType() == EbtBlock) {
478                     if (expressionNode)
479                         parseContext.error(idToken.loc, "buffer aliasing not yet supported", "block initializer", "");
480                     parseContext.declareBlock(idToken.loc, variableType, fullName);
481                     parseContext.declareStructBufferCounter(idToken.loc, variableType, *fullName);
482                 } else {
483                     if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
484                         // this isn't really an individual variable, but a member of the $Global buffer
485                         parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
486                     } else {
487                         // Declare the variable and add any initializer code to the AST.
488                         // The top-level node is always made into an aggregate, as that's
489                         // historically how the AST has been.
490                         initializers = intermediate.growAggregate(initializers,
491                             parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
492                             idToken.loc);
493                     }
494                 }
495             }
496         }
497 
498         // COMMA
499         if (acceptTokenClass(EHTokComma))
500             declarator_list = true;
501     }
502 
503     // The top-level initializer node is a sequence.
504     if (initializers != nullptr)
505         initializers->setOperator(EOpSequence);
506 
507     // if we have a locally scoped static, it needs a globally scoped initializer
508     if (declaredType.getQualifier().storage == EvqGlobal && !parseContext.symbolTable.atGlobalLevel()) {
509         unitNode = intermediate.growAggregate(unitNode, initializers, idToken.loc);
510     } else {
511         // Add the initializers' aggregate to the nodeList we were handed.
512         if (nodeList)
513             nodeList = intermediate.growAggregate(nodeList, initializers);
514         else
515             nodeList = initializers;
516     }
517 
518     // SEMICOLON
519     if (! acceptTokenClass(EHTokSemicolon)) {
520         // This may have been a false detection of what appeared to be a declaration, but
521         // was actually an assignment such as "float = 4", where "float" is an identifier.
522         // We put the token back to let further parsing happen for cases where that may
523         // happen.  This errors on the side of caution, and mostly triggers the error.
524         if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
525             recedeToken();
526         else
527             expected(";");
528         return false;
529     }
530 
531     return true;
532 }
533 
534 // control_declaration
535 //      : fully_specified_type identifier EQUAL expression
536 //
acceptControlDeclaration(TIntermNode * & node)537 bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
538 {
539     node = nullptr;
540     TAttributes attributes;
541 
542     // fully_specified_type
543     TType type;
544     if (! acceptFullySpecifiedType(type, attributes))
545         return false;
546 
547     if (attributes.size() > 0)
548         parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
549 
550     // filter out type casts
551     if (peekTokenClass(EHTokLeftParen)) {
552         recedeToken();
553         return false;
554     }
555 
556     // identifier
557     HlslToken idToken;
558     if (! acceptIdentifier(idToken)) {
559         expected("identifier");
560         return false;
561     }
562 
563     // EQUAL
564     TIntermTyped* expressionNode = nullptr;
565     if (! acceptTokenClass(EHTokAssign)) {
566         expected("=");
567         return false;
568     }
569 
570     // expression
571     if (! acceptExpression(expressionNode)) {
572         expected("initializer");
573         return false;
574     }
575 
576     node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
577 
578     return true;
579 }
580 
581 // fully_specified_type
582 //      : type_specifier
583 //      | type_qualifier type_specifier
584 //
acceptFullySpecifiedType(TType & type,const TAttributes & attributes)585 bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes)
586 {
587     TIntermNode* nodeList = nullptr;
588     return acceptFullySpecifiedType(type, nodeList, attributes);
589 }
acceptFullySpecifiedType(TType & type,TIntermNode * & nodeList,const TAttributes & attributes,bool forbidDeclarators)590 bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators)
591 {
592     // type_qualifier
593     TQualifier qualifier;
594     qualifier.clear();
595     if (! acceptQualifier(qualifier))
596         return false;
597     TSourceLoc loc = token.loc;
598 
599     // type_specifier
600     if (! acceptType(type, nodeList)) {
601         // If this is not a type, we may have inadvertently gone down a wrong path
602         // by parsing "sample", which can be treated like either an identifier or a
603         // qualifier.  Back it out, if we did.
604         if (qualifier.sample)
605             recedeToken();
606 
607         return false;
608     }
609 
610     if (type.getBasicType() == EbtBlock) {
611         // the type was a block, which set some parts of the qualifier
612         parseContext.mergeQualifiers(type.getQualifier(), qualifier);
613 
614         // merge in the attributes
615         parseContext.transferTypeAttributes(token.loc, attributes, type);
616 
617         // further, it can create an anonymous instance of the block
618         // (cbuffer and tbuffer don't consume the next identifier, and
619         // should set forbidDeclarators)
620         if (forbidDeclarators || peek() != EHTokIdentifier)
621             parseContext.declareBlock(loc, type);
622     } else {
623         // Some qualifiers are set when parsing the type.  Merge those with
624         // whatever comes from acceptQualifier.
625         assert(qualifier.layoutFormat == ElfNone);
626 
627         qualifier.layoutFormat = type.getQualifier().layoutFormat;
628         qualifier.precision    = type.getQualifier().precision;
629 
630         if (type.getQualifier().storage == EvqOut ||
631             type.getQualifier().storage == EvqBuffer) {
632             qualifier.storage      = type.getQualifier().storage;
633             qualifier.readonly     = type.getQualifier().readonly;
634         }
635 
636         if (type.isBuiltIn())
637             qualifier.builtIn = type.getQualifier().builtIn;
638 
639         type.getQualifier() = qualifier;
640     }
641 
642     return true;
643 }
644 
645 // type_qualifier
646 //      : qualifier qualifier ...
647 //
648 // Zero or more of these, so this can't return false.
649 //
acceptQualifier(TQualifier & qualifier)650 bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
651 {
652     do {
653         switch (peek()) {
654         case EHTokStatic:
655             qualifier.storage = EvqGlobal;
656             break;
657         case EHTokExtern:
658             // TODO: no meaning in glslang?
659             break;
660         case EHTokShared:
661             // TODO: hint
662             break;
663         case EHTokGroupShared:
664             qualifier.storage = EvqShared;
665             break;
666         case EHTokUniform:
667             qualifier.storage = EvqUniform;
668             break;
669         case EHTokConst:
670             qualifier.storage = EvqConst;
671             break;
672         case EHTokVolatile:
673             qualifier.volatil = true;
674             break;
675         case EHTokLinear:
676             qualifier.smooth = true;
677             break;
678         case EHTokCentroid:
679             qualifier.centroid = true;
680             break;
681         case EHTokNointerpolation:
682             qualifier.flat = true;
683             break;
684         case EHTokNoperspective:
685             qualifier.nopersp = true;
686             break;
687         case EHTokSample:
688             qualifier.sample = true;
689             break;
690         case EHTokRowMajor:
691             qualifier.layoutMatrix = ElmColumnMajor;
692             break;
693         case EHTokColumnMajor:
694             qualifier.layoutMatrix = ElmRowMajor;
695             break;
696         case EHTokPrecise:
697             qualifier.noContraction = true;
698             break;
699         case EHTokIn:
700             qualifier.storage = (qualifier.storage == EvqOut) ? EvqInOut : EvqIn;
701             break;
702         case EHTokOut:
703             qualifier.storage = (qualifier.storage == EvqIn) ? EvqInOut : EvqOut;
704             break;
705         case EHTokInOut:
706             qualifier.storage = EvqInOut;
707             break;
708         case EHTokLayout:
709             if (! acceptLayoutQualifierList(qualifier))
710                 return false;
711             continue;
712         case EHTokGloballyCoherent:
713             qualifier.coherent = true;
714             break;
715         case EHTokInline:
716             // TODO: map this to SPIR-V function control
717             break;
718 
719         // GS geometries: these are specified on stage input variables, and are an error (not verified here)
720         // for output variables.
721         case EHTokPoint:
722             qualifier.storage = EvqIn;
723             if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
724                 return false;
725             break;
726         case EHTokLine:
727             qualifier.storage = EvqIn;
728             if (!parseContext.handleInputGeometry(token.loc, ElgLines))
729                 return false;
730             break;
731         case EHTokTriangle:
732             qualifier.storage = EvqIn;
733             if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
734                 return false;
735             break;
736         case EHTokLineAdj:
737             qualifier.storage = EvqIn;
738             if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
739                 return false;
740             break;
741         case EHTokTriangleAdj:
742             qualifier.storage = EvqIn;
743             if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
744                 return false;
745             break;
746 
747         default:
748             return true;
749         }
750         advanceToken();
751     } while (true);
752 }
753 
754 // layout_qualifier_list
755 //      : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
756 //
757 // layout_qualifier
758 //      : identifier
759 //      | identifier EQUAL expression
760 //
761 // Zero or more of these, so this can't return false.
762 //
acceptLayoutQualifierList(TQualifier & qualifier)763 bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
764 {
765     if (! acceptTokenClass(EHTokLayout))
766         return false;
767 
768     // LEFT_PAREN
769     if (! acceptTokenClass(EHTokLeftParen))
770         return false;
771 
772     do {
773         // identifier
774         HlslToken idToken;
775         if (! acceptIdentifier(idToken))
776             break;
777 
778         // EQUAL expression
779         if (acceptTokenClass(EHTokAssign)) {
780             TIntermTyped* expr;
781             if (! acceptConditionalExpression(expr)) {
782                 expected("expression");
783                 return false;
784             }
785             parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
786         } else
787             parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
788 
789         // COMMA
790         if (! acceptTokenClass(EHTokComma))
791             break;
792     } while (true);
793 
794     // RIGHT_PAREN
795     if (! acceptTokenClass(EHTokRightParen)) {
796         expected(")");
797         return false;
798     }
799 
800     return true;
801 }
802 
803 // template_type
804 //      : FLOAT
805 //      | DOUBLE
806 //      | INT
807 //      | DWORD
808 //      | UINT
809 //      | BOOL
810 //
acceptTemplateVecMatBasicType(TBasicType & basicType)811 bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
812 {
813     switch (peek()) {
814     case EHTokFloat:
815         basicType = EbtFloat;
816         break;
817     case EHTokDouble:
818         basicType = EbtDouble;
819         break;
820     case EHTokInt:
821     case EHTokDword:
822         basicType = EbtInt;
823         break;
824     case EHTokUint:
825         basicType = EbtUint;
826         break;
827     case EHTokBool:
828         basicType = EbtBool;
829         break;
830     default:
831         return false;
832     }
833 
834     advanceToken();
835 
836     return true;
837 }
838 
839 // vector_template_type
840 //      : VECTOR
841 //      | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
842 //
acceptVectorTemplateType(TType & type)843 bool HlslGrammar::acceptVectorTemplateType(TType& type)
844 {
845     if (! acceptTokenClass(EHTokVector))
846         return false;
847 
848     if (! acceptTokenClass(EHTokLeftAngle)) {
849         // in HLSL, 'vector' alone means float4.
850         new(&type) TType(EbtFloat, EvqTemporary, 4);
851         return true;
852     }
853 
854     TBasicType basicType;
855     if (! acceptTemplateVecMatBasicType(basicType)) {
856         expected("scalar type");
857         return false;
858     }
859 
860     // COMMA
861     if (! acceptTokenClass(EHTokComma)) {
862         expected(",");
863         return false;
864     }
865 
866     // integer
867     if (! peekTokenClass(EHTokIntConstant)) {
868         expected("literal integer");
869         return false;
870     }
871 
872     TIntermTyped* vecSize;
873     if (! acceptLiteral(vecSize))
874         return false;
875 
876     const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
877 
878     new(&type) TType(basicType, EvqTemporary, vecSizeI);
879 
880     if (vecSizeI == 1)
881         type.makeVector();
882 
883     if (!acceptTokenClass(EHTokRightAngle)) {
884         expected("right angle bracket");
885         return false;
886     }
887 
888     return true;
889 }
890 
891 // matrix_template_type
892 //      : MATRIX
893 //      | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
894 //
acceptMatrixTemplateType(TType & type)895 bool HlslGrammar::acceptMatrixTemplateType(TType& type)
896 {
897     if (! acceptTokenClass(EHTokMatrix))
898         return false;
899 
900     if (! acceptTokenClass(EHTokLeftAngle)) {
901         // in HLSL, 'matrix' alone means float4x4.
902         new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
903         return true;
904     }
905 
906     TBasicType basicType;
907     if (! acceptTemplateVecMatBasicType(basicType)) {
908         expected("scalar type");
909         return false;
910     }
911 
912     // COMMA
913     if (! acceptTokenClass(EHTokComma)) {
914         expected(",");
915         return false;
916     }
917 
918     // integer rows
919     if (! peekTokenClass(EHTokIntConstant)) {
920         expected("literal integer");
921         return false;
922     }
923 
924     TIntermTyped* rows;
925     if (! acceptLiteral(rows))
926         return false;
927 
928     // COMMA
929     if (! acceptTokenClass(EHTokComma)) {
930         expected(",");
931         return false;
932     }
933 
934     // integer cols
935     if (! peekTokenClass(EHTokIntConstant)) {
936         expected("literal integer");
937         return false;
938     }
939 
940     TIntermTyped* cols;
941     if (! acceptLiteral(cols))
942         return false;
943 
944     new(&type) TType(basicType, EvqTemporary, 0,
945                      rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
946                      cols->getAsConstantUnion()->getConstArray()[0].getIConst());
947 
948     if (!acceptTokenClass(EHTokRightAngle)) {
949         expected("right angle bracket");
950         return false;
951     }
952 
953     return true;
954 }
955 
956 // layout_geometry
957 //      : LINESTREAM
958 //      | POINTSTREAM
959 //      | TRIANGLESTREAM
960 //
acceptOutputPrimitiveGeometry(TLayoutGeometry & geometry)961 bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
962 {
963     // read geometry type
964     const EHlslTokenClass geometryType = peek();
965 
966     switch (geometryType) {
967     case EHTokPointStream:    geometry = ElgPoints;        break;
968     case EHTokLineStream:     geometry = ElgLineStrip;     break;
969     case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
970     default:
971         return false;  // not a layout geometry
972     }
973 
974     advanceToken();  // consume the layout keyword
975     return true;
976 }
977 
978 // tessellation_decl_type
979 //      : INPUTPATCH
980 //      | OUTPUTPATCH
981 //
acceptTessellationDeclType(TBuiltInVariable & patchType)982 bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
983 {
984     // read geometry type
985     const EHlslTokenClass tessType = peek();
986 
987     switch (tessType) {
988     case EHTokInputPatch:    patchType = EbvInputPatch;  break;
989     case EHTokOutputPatch:   patchType = EbvOutputPatch; break;
990     default:
991         return false;  // not a tessellation decl
992     }
993 
994     advanceToken();  // consume the keyword
995     return true;
996 }
997 
998 // tessellation_patch_template_type
999 //      : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
1000 //
acceptTessellationPatchTemplateType(TType & type)1001 bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
1002 {
1003     TBuiltInVariable patchType;
1004 
1005     if (! acceptTessellationDeclType(patchType))
1006         return false;
1007 
1008     if (! acceptTokenClass(EHTokLeftAngle))
1009         return false;
1010 
1011     if (! acceptType(type)) {
1012         expected("tessellation patch type");
1013         return false;
1014     }
1015 
1016     if (! acceptTokenClass(EHTokComma))
1017         return false;
1018 
1019     // integer size
1020     if (! peekTokenClass(EHTokIntConstant)) {
1021         expected("literal integer");
1022         return false;
1023     }
1024 
1025     TIntermTyped* size;
1026     if (! acceptLiteral(size))
1027         return false;
1028 
1029     TArraySizes* arraySizes = new TArraySizes;
1030     arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1031     type.transferArraySizes(arraySizes);
1032     type.getQualifier().builtIn = patchType;
1033 
1034     if (! acceptTokenClass(EHTokRightAngle)) {
1035         expected("right angle bracket");
1036         return false;
1037     }
1038 
1039     return true;
1040 }
1041 
1042 // stream_out_template_type
1043 //      : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1044 //
acceptStreamOutTemplateType(TType & type,TLayoutGeometry & geometry)1045 bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1046 {
1047     geometry = ElgNone;
1048 
1049     if (! acceptOutputPrimitiveGeometry(geometry))
1050         return false;
1051 
1052     if (! acceptTokenClass(EHTokLeftAngle))
1053         return false;
1054 
1055     if (! acceptType(type)) {
1056         expected("stream output type");
1057         return false;
1058     }
1059 
1060     type.getQualifier().storage = EvqOut;
1061     type.getQualifier().builtIn = EbvGsOutputStream;
1062 
1063     if (! acceptTokenClass(EHTokRightAngle)) {
1064         expected("right angle bracket");
1065         return false;
1066     }
1067 
1068     return true;
1069 }
1070 
1071 // annotations
1072 //      : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1073 //
acceptAnnotations(TQualifier &)1074 bool HlslGrammar::acceptAnnotations(TQualifier&)
1075 {
1076     if (! acceptTokenClass(EHTokLeftAngle))
1077         return false;
1078 
1079     // note that we are nesting a name space
1080     parseContext.nestAnnotations();
1081 
1082     // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1083     do {
1084         // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1085         while (acceptTokenClass(EHTokSemicolon))
1086             ;
1087 
1088         if (acceptTokenClass(EHTokRightAngle))
1089             break;
1090 
1091         // declaration
1092         TIntermNode* node = nullptr;
1093         if (! acceptDeclaration(node)) {
1094             expected("declaration in annotation");
1095             return false;
1096         }
1097     } while (true);
1098 
1099     parseContext.unnestAnnotations();
1100     return true;
1101 }
1102 
1103 // subpass input type
1104 //      : SUBPASSINPUT
1105 //      | SUBPASSINPUT VECTOR LEFT_ANGLE template_type RIGHT_ANGLE
1106 //      | SUBPASSINPUTMS
1107 //      | SUBPASSINPUTMS VECTOR LEFT_ANGLE template_type RIGHT_ANGLE
acceptSubpassInputType(TType & type)1108 bool HlslGrammar::acceptSubpassInputType(TType& type)
1109 {
1110     // read subpass type
1111     const EHlslTokenClass subpassInputType = peek();
1112 
1113     bool multisample;
1114 
1115     switch (subpassInputType) {
1116     case EHTokSubpassInput:   multisample = false; break;
1117     case EHTokSubpassInputMS: multisample = true;  break;
1118     default:
1119         return false;  // not a subpass input declaration
1120     }
1121 
1122     advanceToken();  // consume the sampler type keyword
1123 
1124     TType subpassType(EbtFloat, EvqUniform, 4); // default type is float4
1125 
1126     if (acceptTokenClass(EHTokLeftAngle)) {
1127         if (! acceptType(subpassType)) {
1128             expected("scalar or vector type");
1129             return false;
1130         }
1131 
1132         const TBasicType basicRetType = subpassType.getBasicType() ;
1133 
1134         switch (basicRetType) {
1135         case EbtFloat:
1136         case EbtUint:
1137         case EbtInt:
1138         case EbtStruct:
1139             break;
1140         default:
1141             unimplemented("basic type in subpass input");
1142             return false;
1143         }
1144 
1145         if (! acceptTokenClass(EHTokRightAngle)) {
1146             expected("right angle bracket");
1147             return false;
1148         }
1149     }
1150 
1151     const TBasicType subpassBasicType = subpassType.isStruct() ? (*subpassType.getStruct())[0].type->getBasicType()
1152         : subpassType.getBasicType();
1153 
1154     TSampler sampler;
1155     sampler.setSubpass(subpassBasicType, multisample);
1156 
1157     // Remember the declared return type.  Function returns false on error.
1158     if (!parseContext.setTextureReturnType(sampler, subpassType, token.loc))
1159         return false;
1160 
1161     type.shallowCopy(TType(sampler, EvqUniform));
1162 
1163     return true;
1164 }
1165 
1166 // sampler_type for DX9 compatibility
1167 //      : SAMPLER
1168 //      | SAMPLER1D
1169 //      | SAMPLER2D
1170 //      | SAMPLER3D
1171 //      | SAMPLERCUBE
acceptSamplerTypeDX9(TType & type)1172 bool HlslGrammar::acceptSamplerTypeDX9(TType &type)
1173 {
1174     // read sampler type
1175     const EHlslTokenClass samplerType = peek();
1176 
1177     TSamplerDim dim = EsdNone;
1178     TType txType(EbtFloat, EvqUniform, 4); // default type is float4
1179 
1180     bool isShadow = false;
1181 
1182     switch (samplerType)
1183     {
1184     case EHTokSampler:		dim = Esd2D;	break;
1185     case EHTokSampler1d:	dim = Esd1D;	break;
1186     case EHTokSampler2d:	dim = Esd2D;	break;
1187     case EHTokSampler3d:	dim = Esd3D;	break;
1188     case EHTokSamplerCube:	dim = EsdCube;	break;
1189     default:
1190         return false; // not a dx9 sampler declaration
1191     }
1192 
1193     advanceToken(); // consume the sampler type keyword
1194 
1195     TArraySizes *arraySizes = nullptr; // TODO: array
1196 
1197     TSampler sampler;
1198     sampler.set(txType.getBasicType(), dim, false, isShadow, false);
1199 
1200 	if (!parseContext.setTextureReturnType(sampler, txType, token.loc))
1201         return false;
1202 
1203     type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1204     type.getQualifier().layoutFormat = ElfNone;
1205 
1206     return true;
1207 }
1208 
1209 // sampler_type
1210 //      : SAMPLER
1211 //      | SAMPLER1D
1212 //      | SAMPLER2D
1213 //      | SAMPLER3D
1214 //      | SAMPLERCUBE
1215 //      | SAMPLERSTATE
1216 //      | SAMPLERCOMPARISONSTATE
acceptSamplerType(TType & type)1217 bool HlslGrammar::acceptSamplerType(TType& type)
1218 {
1219     // read sampler type
1220     const EHlslTokenClass samplerType = peek();
1221 
1222     // TODO: for DX9
1223     // TSamplerDim dim = EsdNone;
1224 
1225     bool isShadow = false;
1226 
1227     switch (samplerType) {
1228     case EHTokSampler:      break;
1229     case EHTokSampler1d:    /*dim = Esd1D*/; break;
1230     case EHTokSampler2d:    /*dim = Esd2D*/; break;
1231     case EHTokSampler3d:    /*dim = Esd3D*/; break;
1232     case EHTokSamplerCube:  /*dim = EsdCube*/; break;
1233     case EHTokSamplerState: break;
1234     case EHTokSamplerComparisonState: isShadow = true; break;
1235     default:
1236         return false;  // not a sampler declaration
1237     }
1238 
1239     advanceToken();  // consume the sampler type keyword
1240 
1241     TArraySizes* arraySizes = nullptr; // TODO: array
1242 
1243     TSampler sampler;
1244     sampler.setPureSampler(isShadow);
1245 
1246     type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1247 
1248     return true;
1249 }
1250 
1251 // texture_type
1252 //      | BUFFER
1253 //      | TEXTURE1D
1254 //      | TEXTURE1DARRAY
1255 //      | TEXTURE2D
1256 //      | TEXTURE2DARRAY
1257 //      | TEXTURE3D
1258 //      | TEXTURECUBE
1259 //      | TEXTURECUBEARRAY
1260 //      | TEXTURE2DMS
1261 //      | TEXTURE2DMSARRAY
1262 //      | RWBUFFER
1263 //      | RWTEXTURE1D
1264 //      | RWTEXTURE1DARRAY
1265 //      | RWTEXTURE2D
1266 //      | RWTEXTURE2DARRAY
1267 //      | RWTEXTURE3D
1268 
acceptTextureType(TType & type)1269 bool HlslGrammar::acceptTextureType(TType& type)
1270 {
1271     const EHlslTokenClass textureType = peek();
1272 
1273     TSamplerDim dim = EsdNone;
1274     bool array = false;
1275     bool ms    = false;
1276     bool image = false;
1277     bool combined = true;
1278 
1279     switch (textureType) {
1280     case EHTokBuffer:            dim = EsdBuffer; combined = false;    break;
1281     case EHTokTexture1d:         dim = Esd1D;                          break;
1282     case EHTokTexture1darray:    dim = Esd1D; array = true;            break;
1283     case EHTokTexture2d:         dim = Esd2D;                          break;
1284     case EHTokTexture2darray:    dim = Esd2D; array = true;            break;
1285     case EHTokTexture3d:         dim = Esd3D;                          break;
1286     case EHTokTextureCube:       dim = EsdCube;                        break;
1287     case EHTokTextureCubearray:  dim = EsdCube; array = true;          break;
1288     case EHTokTexture2DMS:       dim = Esd2D; ms = true;               break;
1289     case EHTokTexture2DMSarray:  dim = Esd2D; array = true; ms = true; break;
1290     case EHTokRWBuffer:          dim = EsdBuffer; image=true;          break;
1291     case EHTokRWTexture1d:       dim = Esd1D; array=false; image=true; break;
1292     case EHTokRWTexture1darray:  dim = Esd1D; array=true;  image=true; break;
1293     case EHTokRWTexture2d:       dim = Esd2D; array=false; image=true; break;
1294     case EHTokRWTexture2darray:  dim = Esd2D; array=true;  image=true; break;
1295     case EHTokRWTexture3d:       dim = Esd3D; array=false; image=true; break;
1296     default:
1297         return false;  // not a texture declaration
1298     }
1299 
1300     advanceToken();  // consume the texture object keyword
1301 
1302     TType txType(EbtFloat, EvqUniform, 4); // default type is float4
1303 
1304     TIntermTyped* msCount = nullptr;
1305 
1306     // texture type: required for multisample types and RWBuffer/RWTextures!
1307     if (acceptTokenClass(EHTokLeftAngle)) {
1308         if (! acceptType(txType)) {
1309             expected("scalar or vector type");
1310             return false;
1311         }
1312 
1313         const TBasicType basicRetType = txType.getBasicType() ;
1314 
1315         switch (basicRetType) {
1316         case EbtFloat:
1317         case EbtUint:
1318         case EbtInt:
1319         case EbtStruct:
1320             break;
1321         default:
1322             unimplemented("basic type in texture");
1323             return false;
1324         }
1325 
1326         // Buffers can handle small mats if they fit in 4 components
1327         if (dim == EsdBuffer && txType.isMatrix()) {
1328             if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1329                 expected("components < 4 in matrix buffer type");
1330                 return false;
1331             }
1332 
1333             // TODO: except we don't handle it yet...
1334             unimplemented("matrix type in buffer");
1335             return false;
1336         }
1337 
1338         if (!txType.isScalar() && !txType.isVector() && !txType.isStruct()) {
1339             expected("scalar, vector, or struct type");
1340             return false;
1341         }
1342 
1343         if (ms && acceptTokenClass(EHTokComma)) {
1344             // read sample count for multisample types, if given
1345             if (! peekTokenClass(EHTokIntConstant)) {
1346                 expected("multisample count");
1347                 return false;
1348             }
1349 
1350             if (! acceptLiteral(msCount))  // should never fail, since we just found an integer
1351                 return false;
1352         }
1353 
1354         if (! acceptTokenClass(EHTokRightAngle)) {
1355             expected("right angle bracket");
1356             return false;
1357         }
1358     } else if (ms) {
1359         expected("texture type for multisample");
1360         return false;
1361     } else if (image) {
1362         expected("type for RWTexture/RWBuffer");
1363         return false;
1364     }
1365 
1366     TArraySizes* arraySizes = nullptr;
1367     const bool shadow = false; // declared on the sampler
1368 
1369     TSampler sampler;
1370     TLayoutFormat format = ElfNone;
1371 
1372     // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat.  We handle only a limit set.
1373     if (image || dim == EsdBuffer)
1374         format = parseContext.getLayoutFromTxType(token.loc, txType);
1375 
1376     const TBasicType txBasicType = txType.isStruct() ? (*txType.getStruct())[0].type->getBasicType()
1377         : txType.getBasicType();
1378 
1379     // Non-image Buffers are combined
1380     if (dim == EsdBuffer && !image) {
1381         sampler.set(txType.getBasicType(), dim, array);
1382     } else {
1383         // DX10 textures are separated.  TODO: DX9.
1384         if (image) {
1385             sampler.setImage(txBasicType, dim, array, shadow, ms);
1386         } else {
1387             sampler.setTexture(txBasicType, dim, array, shadow, ms);
1388         }
1389     }
1390 
1391     // Remember the declared return type.  Function returns false on error.
1392     if (!parseContext.setTextureReturnType(sampler, txType, token.loc))
1393         return false;
1394 
1395     // Force uncombined, if necessary
1396     if (!combined)
1397         sampler.combined = false;
1398 
1399     type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1400     type.getQualifier().layoutFormat = format;
1401 
1402     return true;
1403 }
1404 
1405 // If token is for a type, update 'type' with the type information,
1406 // and return true and advance.
1407 // Otherwise, return false, and don't advance
acceptType(TType & type)1408 bool HlslGrammar::acceptType(TType& type)
1409 {
1410     TIntermNode* nodeList = nullptr;
1411     return acceptType(type, nodeList);
1412 }
acceptType(TType & type,TIntermNode * & nodeList)1413 bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1414 {
1415     // Basic types for min* types, use native halfs if the option allows them.
1416     bool enable16BitTypes = parseContext.hlslEnable16BitTypes();
1417 
1418     const TBasicType min16float_bt = enable16BitTypes ? EbtFloat16 : EbtFloat;
1419     const TBasicType min10float_bt = enable16BitTypes ? EbtFloat16 : EbtFloat;
1420     const TBasicType half_bt       = enable16BitTypes ? EbtFloat16 : EbtFloat;
1421     const TBasicType min16int_bt   = enable16BitTypes ? EbtInt16   : EbtInt;
1422     const TBasicType min12int_bt   = enable16BitTypes ? EbtInt16   : EbtInt;
1423     const TBasicType min16uint_bt  = enable16BitTypes ? EbtUint16  : EbtUint;
1424 
1425     // Some types might have turned into identifiers. Take the hit for checking
1426     // when this has happened.
1427     if (typeIdentifiers) {
1428         const char* identifierString = getTypeString(peek());
1429         if (identifierString != nullptr) {
1430             TString name = identifierString;
1431             // if it's an identifier, it's not a type
1432             if (parseContext.symbolTable.find(name) != nullptr)
1433                 return false;
1434         }
1435     }
1436 
1437     bool isUnorm = false;
1438     bool isSnorm = false;
1439 
1440     // Accept snorm and unorm.  Presently, this is ignored, save for an error check below.
1441     switch (peek()) {
1442     case EHTokUnorm:
1443         isUnorm = true;
1444         advanceToken();  // eat the token
1445         break;
1446     case EHTokSNorm:
1447         isSnorm = true;
1448         advanceToken();  // eat the token
1449         break;
1450     default:
1451         break;
1452     }
1453 
1454     switch (peek()) {
1455     case EHTokVector:
1456         return acceptVectorTemplateType(type);
1457         break;
1458 
1459     case EHTokMatrix:
1460         return acceptMatrixTemplateType(type);
1461         break;
1462 
1463     case EHTokPointStream:            // fall through
1464     case EHTokLineStream:             // ...
1465     case EHTokTriangleStream:         // ...
1466         {
1467             TLayoutGeometry geometry;
1468             if (! acceptStreamOutTemplateType(type, geometry))
1469                 return false;
1470 
1471             if (! parseContext.handleOutputGeometry(token.loc, geometry))
1472                 return false;
1473 
1474             return true;
1475         }
1476 
1477     case EHTokInputPatch:             // fall through
1478     case EHTokOutputPatch:            // ...
1479         {
1480             if (! acceptTessellationPatchTemplateType(type))
1481                 return false;
1482 
1483             return true;
1484         }
1485 
1486     case EHTokSampler:                // fall through
1487     case EHTokSampler1d:              // ...
1488     case EHTokSampler2d:              // ...
1489     case EHTokSampler3d:              // ...
1490     case EHTokSamplerCube:            // ...
1491         if (parseContext.hlslDX9Compatible())
1492 			return acceptSamplerTypeDX9(type);
1493         else
1494             return acceptSamplerType(type);
1495         break;
1496 
1497     case EHTokSamplerState:           // fall through
1498     case EHTokSamplerComparisonState: // ...
1499         return acceptSamplerType(type);
1500         break;
1501 
1502     case EHTokSubpassInput:           // fall through
1503     case EHTokSubpassInputMS:         // ...
1504         return acceptSubpassInputType(type);
1505         break;
1506 
1507     case EHTokBuffer:                 // fall through
1508     case EHTokTexture1d:              // ...
1509     case EHTokTexture1darray:         // ...
1510     case EHTokTexture2d:              // ...
1511     case EHTokTexture2darray:         // ...
1512     case EHTokTexture3d:              // ...
1513     case EHTokTextureCube:            // ...
1514     case EHTokTextureCubearray:       // ...
1515     case EHTokTexture2DMS:            // ...
1516     case EHTokTexture2DMSarray:       // ...
1517     case EHTokRWTexture1d:            // ...
1518     case EHTokRWTexture1darray:       // ...
1519     case EHTokRWTexture2d:            // ...
1520     case EHTokRWTexture2darray:       // ...
1521     case EHTokRWTexture3d:            // ...
1522     case EHTokRWBuffer:               // ...
1523         return acceptTextureType(type);
1524         break;
1525 
1526     case EHTokAppendStructuredBuffer:
1527     case EHTokByteAddressBuffer:
1528     case EHTokConsumeStructuredBuffer:
1529     case EHTokRWByteAddressBuffer:
1530     case EHTokRWStructuredBuffer:
1531     case EHTokStructuredBuffer:
1532         return acceptStructBufferType(type);
1533         break;
1534 
1535     case EHTokTextureBuffer:
1536         return acceptTextureBufferType(type);
1537         break;
1538 
1539     case EHTokConstantBuffer:
1540         return acceptConstantBufferType(type);
1541 
1542     case EHTokClass:
1543     case EHTokStruct:
1544     case EHTokCBuffer:
1545     case EHTokTBuffer:
1546         return acceptStruct(type, nodeList);
1547 
1548     case EHTokIdentifier:
1549         // An identifier could be for a user-defined type.
1550         // Note we cache the symbol table lookup, to save for a later rule
1551         // when this is not a type.
1552         if (parseContext.lookupUserType(*token.string, type) != nullptr) {
1553             advanceToken();
1554             return true;
1555         } else
1556             return false;
1557 
1558     case EHTokVoid:
1559         new(&type) TType(EbtVoid);
1560         break;
1561 
1562     case EHTokString:
1563         new(&type) TType(EbtString);
1564         break;
1565 
1566     case EHTokFloat:
1567         new(&type) TType(EbtFloat);
1568         break;
1569     case EHTokFloat1:
1570         new(&type) TType(EbtFloat);
1571         type.makeVector();
1572         break;
1573     case EHTokFloat2:
1574         new(&type) TType(EbtFloat, EvqTemporary, 2);
1575         break;
1576     case EHTokFloat3:
1577         new(&type) TType(EbtFloat, EvqTemporary, 3);
1578         break;
1579     case EHTokFloat4:
1580         new(&type) TType(EbtFloat, EvqTemporary, 4);
1581         break;
1582 
1583     case EHTokDouble:
1584         new(&type) TType(EbtDouble);
1585         break;
1586     case EHTokDouble1:
1587         new(&type) TType(EbtDouble);
1588         type.makeVector();
1589         break;
1590     case EHTokDouble2:
1591         new(&type) TType(EbtDouble, EvqTemporary, 2);
1592         break;
1593     case EHTokDouble3:
1594         new(&type) TType(EbtDouble, EvqTemporary, 3);
1595         break;
1596     case EHTokDouble4:
1597         new(&type) TType(EbtDouble, EvqTemporary, 4);
1598         break;
1599 
1600     case EHTokInt:
1601     case EHTokDword:
1602         new(&type) TType(EbtInt);
1603         break;
1604     case EHTokInt1:
1605         new(&type) TType(EbtInt);
1606         type.makeVector();
1607         break;
1608     case EHTokInt2:
1609         new(&type) TType(EbtInt, EvqTemporary, 2);
1610         break;
1611     case EHTokInt3:
1612         new(&type) TType(EbtInt, EvqTemporary, 3);
1613         break;
1614     case EHTokInt4:
1615         new(&type) TType(EbtInt, EvqTemporary, 4);
1616         break;
1617 
1618     case EHTokUint:
1619         new(&type) TType(EbtUint);
1620         break;
1621     case EHTokUint1:
1622         new(&type) TType(EbtUint);
1623         type.makeVector();
1624         break;
1625     case EHTokUint2:
1626         new(&type) TType(EbtUint, EvqTemporary, 2);
1627         break;
1628     case EHTokUint3:
1629         new(&type) TType(EbtUint, EvqTemporary, 3);
1630         break;
1631     case EHTokUint4:
1632         new(&type) TType(EbtUint, EvqTemporary, 4);
1633         break;
1634 
1635     case EHTokUint64:
1636         new(&type) TType(EbtUint64);
1637         break;
1638 
1639     case EHTokBool:
1640         new(&type) TType(EbtBool);
1641         break;
1642     case EHTokBool1:
1643         new(&type) TType(EbtBool);
1644         type.makeVector();
1645         break;
1646     case EHTokBool2:
1647         new(&type) TType(EbtBool, EvqTemporary, 2);
1648         break;
1649     case EHTokBool3:
1650         new(&type) TType(EbtBool, EvqTemporary, 3);
1651         break;
1652     case EHTokBool4:
1653         new(&type) TType(EbtBool, EvqTemporary, 4);
1654         break;
1655 
1656     case EHTokHalf:
1657         new(&type) TType(half_bt, EvqTemporary);
1658         break;
1659     case EHTokHalf1:
1660         new(&type) TType(half_bt, EvqTemporary);
1661         type.makeVector();
1662         break;
1663     case EHTokHalf2:
1664         new(&type) TType(half_bt, EvqTemporary, 2);
1665         break;
1666     case EHTokHalf3:
1667         new(&type) TType(half_bt, EvqTemporary, 3);
1668         break;
1669     case EHTokHalf4:
1670         new(&type) TType(half_bt, EvqTemporary, 4);
1671         break;
1672 
1673     case EHTokMin16float:
1674         new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1675         break;
1676     case EHTokMin16float1:
1677         new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1678         type.makeVector();
1679         break;
1680     case EHTokMin16float2:
1681         new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1682         break;
1683     case EHTokMin16float3:
1684         new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1685         break;
1686     case EHTokMin16float4:
1687         new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1688         break;
1689 
1690     case EHTokMin10float:
1691         new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1692         break;
1693     case EHTokMin10float1:
1694         new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1695         type.makeVector();
1696         break;
1697     case EHTokMin10float2:
1698         new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1699         break;
1700     case EHTokMin10float3:
1701         new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1702         break;
1703     case EHTokMin10float4:
1704         new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1705         break;
1706 
1707     case EHTokMin16int:
1708         new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1709         break;
1710     case EHTokMin16int1:
1711         new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1712         type.makeVector();
1713         break;
1714     case EHTokMin16int2:
1715         new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1716         break;
1717     case EHTokMin16int3:
1718         new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1719         break;
1720     case EHTokMin16int4:
1721         new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1722         break;
1723 
1724     case EHTokMin12int:
1725         new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1726         break;
1727     case EHTokMin12int1:
1728         new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1729         type.makeVector();
1730         break;
1731     case EHTokMin12int2:
1732         new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1733         break;
1734     case EHTokMin12int3:
1735         new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1736         break;
1737     case EHTokMin12int4:
1738         new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1739         break;
1740 
1741     case EHTokMin16uint:
1742         new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1743         break;
1744     case EHTokMin16uint1:
1745         new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1746         type.makeVector();
1747         break;
1748     case EHTokMin16uint2:
1749         new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1750         break;
1751     case EHTokMin16uint3:
1752         new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1753         break;
1754     case EHTokMin16uint4:
1755         new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1756         break;
1757 
1758     case EHTokInt1x1:
1759         new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1760         break;
1761     case EHTokInt1x2:
1762         new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
1763         break;
1764     case EHTokInt1x3:
1765         new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
1766         break;
1767     case EHTokInt1x4:
1768         new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
1769         break;
1770     case EHTokInt2x1:
1771         new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
1772         break;
1773     case EHTokInt2x2:
1774         new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1775         break;
1776     case EHTokInt2x3:
1777         new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
1778         break;
1779     case EHTokInt2x4:
1780         new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
1781         break;
1782     case EHTokInt3x1:
1783         new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
1784         break;
1785     case EHTokInt3x2:
1786         new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
1787         break;
1788     case EHTokInt3x3:
1789         new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1790         break;
1791     case EHTokInt3x4:
1792         new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
1793         break;
1794     case EHTokInt4x1:
1795         new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
1796         break;
1797     case EHTokInt4x2:
1798         new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
1799         break;
1800     case EHTokInt4x3:
1801         new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
1802         break;
1803     case EHTokInt4x4:
1804         new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1805         break;
1806 
1807     case EHTokUint1x1:
1808         new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1809         break;
1810     case EHTokUint1x2:
1811         new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
1812         break;
1813     case EHTokUint1x3:
1814         new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
1815         break;
1816     case EHTokUint1x4:
1817         new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
1818         break;
1819     case EHTokUint2x1:
1820         new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
1821         break;
1822     case EHTokUint2x2:
1823         new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1824         break;
1825     case EHTokUint2x3:
1826         new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
1827         break;
1828     case EHTokUint2x4:
1829         new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
1830         break;
1831     case EHTokUint3x1:
1832         new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
1833         break;
1834     case EHTokUint3x2:
1835         new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
1836         break;
1837     case EHTokUint3x3:
1838         new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1839         break;
1840     case EHTokUint3x4:
1841         new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
1842         break;
1843     case EHTokUint4x1:
1844         new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
1845         break;
1846     case EHTokUint4x2:
1847         new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
1848         break;
1849     case EHTokUint4x3:
1850         new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
1851         break;
1852     case EHTokUint4x4:
1853         new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1854         break;
1855 
1856     case EHTokBool1x1:
1857         new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1858         break;
1859     case EHTokBool1x2:
1860         new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
1861         break;
1862     case EHTokBool1x3:
1863         new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
1864         break;
1865     case EHTokBool1x4:
1866         new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
1867         break;
1868     case EHTokBool2x1:
1869         new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
1870         break;
1871     case EHTokBool2x2:
1872         new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1873         break;
1874     case EHTokBool2x3:
1875         new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
1876         break;
1877     case EHTokBool2x4:
1878         new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
1879         break;
1880     case EHTokBool3x1:
1881         new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
1882         break;
1883     case EHTokBool3x2:
1884         new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
1885         break;
1886     case EHTokBool3x3:
1887         new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1888         break;
1889     case EHTokBool3x4:
1890         new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
1891         break;
1892     case EHTokBool4x1:
1893         new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
1894         break;
1895     case EHTokBool4x2:
1896         new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
1897         break;
1898     case EHTokBool4x3:
1899         new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
1900         break;
1901     case EHTokBool4x4:
1902         new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1903         break;
1904 
1905     case EHTokFloat1x1:
1906         new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1907         break;
1908     case EHTokFloat1x2:
1909         new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
1910         break;
1911     case EHTokFloat1x3:
1912         new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
1913         break;
1914     case EHTokFloat1x4:
1915         new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
1916         break;
1917     case EHTokFloat2x1:
1918         new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
1919         break;
1920     case EHTokFloat2x2:
1921         new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1922         break;
1923     case EHTokFloat2x3:
1924         new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
1925         break;
1926     case EHTokFloat2x4:
1927         new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
1928         break;
1929     case EHTokFloat3x1:
1930         new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
1931         break;
1932     case EHTokFloat3x2:
1933         new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
1934         break;
1935     case EHTokFloat3x3:
1936         new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1937         break;
1938     case EHTokFloat3x4:
1939         new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
1940         break;
1941     case EHTokFloat4x1:
1942         new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
1943         break;
1944     case EHTokFloat4x2:
1945         new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
1946         break;
1947     case EHTokFloat4x3:
1948         new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
1949         break;
1950     case EHTokFloat4x4:
1951         new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1952         break;
1953 
1954     case EHTokHalf1x1:
1955         new(&type) TType(half_bt, EvqTemporary, 0, 1, 1);
1956         break;
1957     case EHTokHalf1x2:
1958         new(&type) TType(half_bt, EvqTemporary, 0, 1, 2);
1959         break;
1960     case EHTokHalf1x3:
1961         new(&type) TType(half_bt, EvqTemporary, 0, 1, 3);
1962         break;
1963     case EHTokHalf1x4:
1964         new(&type) TType(half_bt, EvqTemporary, 0, 1, 4);
1965         break;
1966     case EHTokHalf2x1:
1967         new(&type) TType(half_bt, EvqTemporary, 0, 2, 1);
1968         break;
1969     case EHTokHalf2x2:
1970         new(&type) TType(half_bt, EvqTemporary, 0, 2, 2);
1971         break;
1972     case EHTokHalf2x3:
1973         new(&type) TType(half_bt, EvqTemporary, 0, 2, 3);
1974         break;
1975     case EHTokHalf2x4:
1976         new(&type) TType(half_bt, EvqTemporary, 0, 2, 4);
1977         break;
1978     case EHTokHalf3x1:
1979         new(&type) TType(half_bt, EvqTemporary, 0, 3, 1);
1980         break;
1981     case EHTokHalf3x2:
1982         new(&type) TType(half_bt, EvqTemporary, 0, 3, 2);
1983         break;
1984     case EHTokHalf3x3:
1985         new(&type) TType(half_bt, EvqTemporary, 0, 3, 3);
1986         break;
1987     case EHTokHalf3x4:
1988         new(&type) TType(half_bt, EvqTemporary, 0, 3, 4);
1989         break;
1990     case EHTokHalf4x1:
1991         new(&type) TType(half_bt, EvqTemporary, 0, 4, 1);
1992         break;
1993     case EHTokHalf4x2:
1994         new(&type) TType(half_bt, EvqTemporary, 0, 4, 2);
1995         break;
1996     case EHTokHalf4x3:
1997         new(&type) TType(half_bt, EvqTemporary, 0, 4, 3);
1998         break;
1999     case EHTokHalf4x4:
2000         new(&type) TType(half_bt, EvqTemporary, 0, 4, 4);
2001         break;
2002 
2003     case EHTokDouble1x1:
2004         new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
2005         break;
2006     case EHTokDouble1x2:
2007         new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
2008         break;
2009     case EHTokDouble1x3:
2010         new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
2011         break;
2012     case EHTokDouble1x4:
2013         new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
2014         break;
2015     case EHTokDouble2x1:
2016         new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
2017         break;
2018     case EHTokDouble2x2:
2019         new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
2020         break;
2021     case EHTokDouble2x3:
2022         new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
2023         break;
2024     case EHTokDouble2x4:
2025         new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
2026         break;
2027     case EHTokDouble3x1:
2028         new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
2029         break;
2030     case EHTokDouble3x2:
2031         new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
2032         break;
2033     case EHTokDouble3x3:
2034         new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
2035         break;
2036     case EHTokDouble3x4:
2037         new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
2038         break;
2039     case EHTokDouble4x1:
2040         new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
2041         break;
2042     case EHTokDouble4x2:
2043         new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
2044         break;
2045     case EHTokDouble4x3:
2046         new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
2047         break;
2048     case EHTokDouble4x4:
2049         new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
2050         break;
2051 
2052     default:
2053         return false;
2054     }
2055 
2056     advanceToken();
2057 
2058     if ((isUnorm || isSnorm) && !type.isFloatingDomain()) {
2059         parseContext.error(token.loc, "unorm and snorm only valid in floating point domain", "", "");
2060         return false;
2061     }
2062 
2063     return true;
2064 }
2065 
2066 // struct
2067 //      : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
2068 //      | struct_type            post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
2069 //      | struct_type IDENTIFIER // use of previously declared struct type
2070 //
2071 // struct_type
2072 //      : STRUCT
2073 //      | CLASS
2074 //      | CBUFFER
2075 //      | TBUFFER
2076 //
acceptStruct(TType & type,TIntermNode * & nodeList)2077 bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
2078 {
2079     // This storage qualifier will tell us whether it's an AST
2080     // block type or just a generic structure type.
2081     TStorageQualifier storageQualifier = EvqTemporary;
2082     bool readonly = false;
2083 
2084     if (acceptTokenClass(EHTokCBuffer)) {
2085         // CBUFFER
2086         storageQualifier = EvqUniform;
2087     } else if (acceptTokenClass(EHTokTBuffer)) {
2088         // TBUFFER
2089         storageQualifier = EvqBuffer;
2090         readonly = true;
2091     } else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct)) {
2092         // Neither CLASS nor STRUCT
2093         return false;
2094     }
2095 
2096     // Now known to be one of CBUFFER, TBUFFER, CLASS, or STRUCT
2097 
2098 
2099     // IDENTIFIER.  It might also be a keyword which can double as an identifier.
2100     // For example:  'cbuffer ConstantBuffer' or 'struct ConstantBuffer' is legal.
2101     // 'cbuffer int' is also legal, and 'struct int' appears rejected only because
2102     // it attempts to redefine the 'int' type.
2103     const char* idString = getTypeString(peek());
2104     TString structName = "";
2105     if (peekTokenClass(EHTokIdentifier) || idString != nullptr) {
2106         if (idString != nullptr)
2107             structName = *idString;
2108         else
2109             structName = *token.string;
2110         advanceToken();
2111     }
2112 
2113     // post_decls
2114     TQualifier postDeclQualifier;
2115     postDeclQualifier.clear();
2116     bool postDeclsFound = acceptPostDecls(postDeclQualifier);
2117 
2118     // LEFT_BRACE, or
2119     // struct_type IDENTIFIER
2120     if (! acceptTokenClass(EHTokLeftBrace)) {
2121         if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
2122             // struct_type IDENTIFIER
2123             return true;
2124         } else {
2125             expected("{");
2126             return false;
2127         }
2128     }
2129 
2130 
2131     // struct_declaration_list
2132     TTypeList* typeList;
2133     // Save each member function so they can be processed after we have a fully formed 'this'.
2134     TVector<TFunctionDeclarator> functionDeclarators;
2135 
2136     parseContext.pushNamespace(structName);
2137     bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
2138     parseContext.popNamespace();
2139 
2140     if (! acceptedList) {
2141         expected("struct member declarations");
2142         return false;
2143     }
2144 
2145     // RIGHT_BRACE
2146     if (! acceptTokenClass(EHTokRightBrace)) {
2147         expected("}");
2148         return false;
2149     }
2150 
2151     // create the user-defined type
2152     if (storageQualifier == EvqTemporary)
2153         new(&type) TType(typeList, structName);
2154     else {
2155         postDeclQualifier.storage = storageQualifier;
2156         postDeclQualifier.readonly = readonly;
2157         new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
2158     }
2159 
2160     parseContext.declareStruct(token.loc, structName, type);
2161 
2162     // For member functions: now that we know the type of 'this', go back and
2163     // - add their implicit argument with 'this' (not to the mangling, just the argument list)
2164     // - parse the functions, their tokens were saved for deferred parsing (now)
2165     for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
2166         // update signature
2167         if (functionDeclarators[b].function->hasImplicitThis())
2168             functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
2169     }
2170 
2171     // All member functions get parsed inside the class/struct namespace and with the
2172     // class/struct members in a symbol-table level.
2173     parseContext.pushNamespace(structName);
2174     parseContext.pushThisScope(type, functionDeclarators);
2175     bool deferredSuccess = true;
2176     for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
2177         // parse body
2178         pushTokenStream(functionDeclarators[b].body);
2179         if (! acceptFunctionBody(functionDeclarators[b], nodeList))
2180             deferredSuccess = false;
2181         popTokenStream();
2182     }
2183     parseContext.popThisScope();
2184     parseContext.popNamespace();
2185 
2186     return deferredSuccess;
2187 }
2188 
2189 // constantbuffer
2190 //    : CONSTANTBUFFER LEFT_ANGLE type RIGHT_ANGLE
acceptConstantBufferType(TType & type)2191 bool HlslGrammar::acceptConstantBufferType(TType& type)
2192 {
2193     if (! acceptTokenClass(EHTokConstantBuffer))
2194         return false;
2195 
2196     if (! acceptTokenClass(EHTokLeftAngle)) {
2197         expected("left angle bracket");
2198         return false;
2199     }
2200 
2201     TType templateType;
2202     if (! acceptType(templateType)) {
2203         expected("type");
2204         return false;
2205     }
2206 
2207     if (! acceptTokenClass(EHTokRightAngle)) {
2208         expected("right angle bracket");
2209         return false;
2210     }
2211 
2212     TQualifier postDeclQualifier;
2213     postDeclQualifier.clear();
2214     postDeclQualifier.storage = EvqUniform;
2215 
2216     if (templateType.isStruct()) {
2217         // Make a block from the type parsed as the template argument
2218         TTypeList* typeList = templateType.getWritableStruct();
2219         new(&type) TType(typeList, "", postDeclQualifier); // sets EbtBlock
2220 
2221         type.getQualifier().storage = EvqUniform;
2222 
2223         return true;
2224     } else {
2225         parseContext.error(token.loc, "non-structure type in ConstantBuffer", "", "");
2226         return false;
2227     }
2228 }
2229 
2230 // texture_buffer
2231 //    : TEXTUREBUFFER LEFT_ANGLE type RIGHT_ANGLE
acceptTextureBufferType(TType & type)2232 bool HlslGrammar::acceptTextureBufferType(TType& type)
2233 {
2234     if (! acceptTokenClass(EHTokTextureBuffer))
2235         return false;
2236 
2237     if (! acceptTokenClass(EHTokLeftAngle)) {
2238         expected("left angle bracket");
2239         return false;
2240     }
2241 
2242     TType templateType;
2243     if (! acceptType(templateType)) {
2244         expected("type");
2245         return false;
2246     }
2247 
2248     if (! acceptTokenClass(EHTokRightAngle)) {
2249         expected("right angle bracket");
2250         return false;
2251     }
2252 
2253     templateType.getQualifier().storage = EvqBuffer;
2254     templateType.getQualifier().readonly = true;
2255 
2256     TType blockType(templateType.getWritableStruct(), "", templateType.getQualifier());
2257 
2258     blockType.getQualifier().storage = EvqBuffer;
2259     blockType.getQualifier().readonly = true;
2260 
2261     type.shallowCopy(blockType);
2262 
2263     return true;
2264 }
2265 
2266 
2267 // struct_buffer
2268 //    : APPENDSTRUCTUREDBUFFER
2269 //    | BYTEADDRESSBUFFER
2270 //    | CONSUMESTRUCTUREDBUFFER
2271 //    | RWBYTEADDRESSBUFFER
2272 //    | RWSTRUCTUREDBUFFER
2273 //    | STRUCTUREDBUFFER
acceptStructBufferType(TType & type)2274 bool HlslGrammar::acceptStructBufferType(TType& type)
2275 {
2276     const EHlslTokenClass structBuffType = peek();
2277 
2278     // TODO: globallycoherent
2279     bool hasTemplateType = true;
2280     bool readonly = false;
2281 
2282     TStorageQualifier storage = EvqBuffer;
2283     TBuiltInVariable  builtinType = EbvNone;
2284 
2285     switch (structBuffType) {
2286     case EHTokAppendStructuredBuffer:
2287         builtinType = EbvAppendConsume;
2288         break;
2289     case EHTokByteAddressBuffer:
2290         hasTemplateType = false;
2291         readonly = true;
2292         builtinType = EbvByteAddressBuffer;
2293         break;
2294     case EHTokConsumeStructuredBuffer:
2295         builtinType = EbvAppendConsume;
2296         break;
2297     case EHTokRWByteAddressBuffer:
2298         hasTemplateType = false;
2299         builtinType = EbvRWByteAddressBuffer;
2300         break;
2301     case EHTokRWStructuredBuffer:
2302         builtinType = EbvRWStructuredBuffer;
2303         break;
2304     case EHTokStructuredBuffer:
2305         builtinType = EbvStructuredBuffer;
2306         readonly = true;
2307         break;
2308     default:
2309         return false;  // not a structure buffer type
2310     }
2311 
2312     advanceToken();  // consume the structure keyword
2313 
2314     // type on which this StructedBuffer is templatized.  E.g, StructedBuffer<MyStruct> ==> MyStruct
2315     TType* templateType = new TType;
2316 
2317     if (hasTemplateType) {
2318         if (! acceptTokenClass(EHTokLeftAngle)) {
2319             expected("left angle bracket");
2320             return false;
2321         }
2322 
2323         if (! acceptType(*templateType)) {
2324             expected("type");
2325             return false;
2326         }
2327         if (! acceptTokenClass(EHTokRightAngle)) {
2328             expected("right angle bracket");
2329             return false;
2330         }
2331     } else {
2332         // byte address buffers have no explicit type.
2333         TType uintType(EbtUint, storage);
2334         templateType->shallowCopy(uintType);
2335     }
2336 
2337     // Create an unsized array out of that type.
2338     // TODO: does this work if it's already an array type?
2339     TArraySizes* unsizedArray = new TArraySizes;
2340     unsizedArray->addInnerSize(UnsizedArraySize);
2341     templateType->transferArraySizes(unsizedArray);
2342     templateType->getQualifier().storage = storage;
2343 
2344     // field name is canonical for all structbuffers
2345     templateType->setFieldName("@data");
2346 
2347     TTypeList* blockStruct = new TTypeList;
2348     TTypeLoc  member = { templateType, token.loc };
2349     blockStruct->push_back(member);
2350 
2351     // This is the type of the buffer block (SSBO)
2352     TType blockType(blockStruct, "", templateType->getQualifier());
2353 
2354     blockType.getQualifier().storage = storage;
2355     blockType.getQualifier().readonly = readonly;
2356     blockType.getQualifier().builtIn = builtinType;
2357 
2358     // We may have created an equivalent type before, in which case we should use its
2359     // deep structure.
2360     parseContext.shareStructBufferType(blockType);
2361 
2362     type.shallowCopy(blockType);
2363 
2364     return true;
2365 }
2366 
2367 // struct_declaration_list
2368 //      : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2369 //
2370 // struct_declaration
2371 //      : attributes fully_specified_type struct_declarator COMMA struct_declarator ...
2372 //      | attributes fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
2373 //
2374 // struct_declarator
2375 //      : IDENTIFIER post_decls
2376 //      | IDENTIFIER array_specifier post_decls
2377 //      | IDENTIFIER function_parameters post_decls                                         // member-function prototype
2378 //
acceptStructDeclarationList(TTypeList * & typeList,TIntermNode * & nodeList,TVector<TFunctionDeclarator> & declarators)2379 bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
2380                                               TVector<TFunctionDeclarator>& declarators)
2381 {
2382     typeList = new TTypeList();
2383     HlslToken idToken;
2384 
2385     do {
2386         // success on seeing the RIGHT_BRACE coming up
2387         if (peekTokenClass(EHTokRightBrace))
2388             break;
2389 
2390         // struct_declaration
2391 
2392         // attributes
2393         TAttributes attributes;
2394         acceptAttributes(attributes);
2395 
2396         bool declarator_list = false;
2397 
2398         // fully_specified_type
2399         TType memberType;
2400         if (! acceptFullySpecifiedType(memberType, nodeList, attributes)) {
2401             expected("member type");
2402             return false;
2403         }
2404 
2405         // merge in the attributes
2406         parseContext.transferTypeAttributes(token.loc, attributes, memberType);
2407 
2408         // struct_declarator COMMA struct_declarator ...
2409         bool functionDefinitionAccepted = false;
2410         do {
2411             if (! acceptIdentifier(idToken)) {
2412                 expected("member name");
2413                 return false;
2414             }
2415 
2416             if (peekTokenClass(EHTokLeftParen)) {
2417                 // function_parameters
2418                 if (!declarator_list) {
2419                     declarators.resize(declarators.size() + 1);
2420                     // request a token stream for deferred processing
2421                     functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2422                                                                                 declarators.back());
2423                     if (functionDefinitionAccepted)
2424                         break;
2425                 }
2426                 expected("member-function definition");
2427                 return false;
2428             } else {
2429                 // add it to the list of members
2430                 TTypeLoc member = { new TType(EbtVoid), token.loc };
2431                 member.type->shallowCopy(memberType);
2432                 member.type->setFieldName(*idToken.string);
2433                 typeList->push_back(member);
2434 
2435                 // array_specifier
2436                 TArraySizes* arraySizes = nullptr;
2437                 acceptArraySpecifier(arraySizes);
2438                 if (arraySizes)
2439                     typeList->back().type->transferArraySizes(arraySizes);
2440 
2441                 acceptPostDecls(member.type->getQualifier());
2442 
2443                 // EQUAL assignment_expression
2444                 if (acceptTokenClass(EHTokAssign)) {
2445                     parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2446                     TIntermTyped* expressionNode = nullptr;
2447                     if (! acceptAssignmentExpression(expressionNode)) {
2448                         expected("initializer");
2449                         return false;
2450                     }
2451                 }
2452             }
2453             // success on seeing the SEMICOLON coming up
2454             if (peekTokenClass(EHTokSemicolon))
2455                 break;
2456 
2457             // COMMA
2458             if (acceptTokenClass(EHTokComma))
2459                 declarator_list = true;
2460             else {
2461                 expected(",");
2462                 return false;
2463             }
2464 
2465         } while (true);
2466 
2467         // SEMI_COLON
2468         if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
2469             expected(";");
2470             return false;
2471         }
2472 
2473     } while (true);
2474 
2475     return true;
2476 }
2477 
2478 // member_function_definition
2479 //    | function_parameters post_decls compound_statement
2480 //
2481 // Expects type to have EvqGlobal for a static member and
2482 // EvqTemporary for non-static member.
acceptMemberFunctionDefinition(TIntermNode * & nodeList,const TType & type,TString & memberName,TFunctionDeclarator & declarator)2483 bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, TString& memberName,
2484                                                  TFunctionDeclarator& declarator)
2485 {
2486     bool accepted = false;
2487 
2488     TString* functionName = &memberName;
2489     parseContext.getFullNamespaceName(functionName);
2490     declarator.function = new TFunction(functionName, type);
2491     if (type.getQualifier().storage == EvqTemporary)
2492         declarator.function->setImplicitThis();
2493     else
2494         declarator.function->setIllegalImplicitThis();
2495 
2496     // function_parameters
2497     if (acceptFunctionParameters(*declarator.function)) {
2498         // post_decls
2499         acceptPostDecls(declarator.function->getWritableType().getQualifier());
2500 
2501         // compound_statement (function body definition)
2502         if (peekTokenClass(EHTokLeftBrace)) {
2503             declarator.loc = token.loc;
2504             declarator.body = new TVector<HlslToken>;
2505             accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
2506         }
2507     } else
2508         expected("function parameter list");
2509 
2510     return accepted;
2511 }
2512 
2513 // function_parameters
2514 //      : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
2515 //      | LEFT_PAREN VOID RIGHT_PAREN
2516 //
acceptFunctionParameters(TFunction & function)2517 bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2518 {
2519     // LEFT_PAREN
2520     if (! acceptTokenClass(EHTokLeftParen))
2521         return false;
2522 
2523     // VOID RIGHT_PAREN
2524     if (! acceptTokenClass(EHTokVoid)) {
2525         do {
2526             // parameter_declaration
2527             if (! acceptParameterDeclaration(function))
2528                 break;
2529 
2530             // COMMA
2531             if (! acceptTokenClass(EHTokComma))
2532                 break;
2533         } while (true);
2534     }
2535 
2536     // RIGHT_PAREN
2537     if (! acceptTokenClass(EHTokRightParen)) {
2538         expected(")");
2539         return false;
2540     }
2541 
2542     return true;
2543 }
2544 
2545 // default_parameter_declaration
2546 //      : EQUAL conditional_expression
2547 //      : EQUAL initializer
acceptDefaultParameterDeclaration(const TType & type,TIntermTyped * & node)2548 bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2549 {
2550     node = nullptr;
2551 
2552     // Valid not to have a default_parameter_declaration
2553     if (!acceptTokenClass(EHTokAssign))
2554         return true;
2555 
2556     if (!acceptConditionalExpression(node)) {
2557         if (!acceptInitializer(node))
2558             return false;
2559 
2560         // For initializer lists, we have to const-fold into a constructor for the type, so build
2561         // that.
2562         TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
2563         if (constructor == nullptr)  // cannot construct
2564             return false;
2565 
2566         TIntermTyped* arguments = nullptr;
2567         for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
2568             parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
2569 
2570         node = parseContext.handleFunctionCall(token.loc, constructor, node);
2571     }
2572 
2573     if (node == nullptr)
2574         return false;
2575 
2576     // If this is simply a constant, we can use it directly.
2577     if (node->getAsConstantUnion())
2578         return true;
2579 
2580     // Otherwise, it has to be const-foldable.
2581     TIntermTyped* origNode = node;
2582 
2583     node = intermediate.fold(node->getAsAggregate());
2584 
2585     if (node != nullptr && origNode != node)
2586         return true;
2587 
2588     parseContext.error(token.loc, "invalid default parameter value", "", "");
2589 
2590     return false;
2591 }
2592 
2593 // parameter_declaration
2594 //      : attributes attributed_declaration
2595 //
2596 // attributed_declaration
2597 //      : fully_specified_type post_decls [ = default_parameter_declaration ]
2598 //      | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
2599 //
acceptParameterDeclaration(TFunction & function)2600 bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2601 {
2602     // attributes
2603     TAttributes attributes;
2604     acceptAttributes(attributes);
2605 
2606     // fully_specified_type
2607     TType* type = new TType;
2608     if (! acceptFullySpecifiedType(*type, attributes))
2609         return false;
2610 
2611     // merge in the attributes
2612     parseContext.transferTypeAttributes(token.loc, attributes, *type);
2613 
2614     // identifier
2615     HlslToken idToken;
2616     acceptIdentifier(idToken);
2617 
2618     // array_specifier
2619     TArraySizes* arraySizes = nullptr;
2620     acceptArraySpecifier(arraySizes);
2621     if (arraySizes) {
2622         if (arraySizes->hasUnsized()) {
2623             parseContext.error(token.loc, "function parameter requires array size", "[]", "");
2624             return false;
2625         }
2626 
2627         type->transferArraySizes(arraySizes);
2628     }
2629 
2630     // post_decls
2631     acceptPostDecls(type->getQualifier());
2632 
2633     TIntermTyped* defaultValue;
2634     if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2635         return false;
2636 
2637     parseContext.paramFix(*type);
2638 
2639     // If any prior parameters have default values, all the parameters after that must as well.
2640     if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2641         parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2642         return false;
2643     }
2644 
2645     TParameter param = { idToken.string, type, defaultValue };
2646     function.addParameter(param);
2647 
2648     return true;
2649 }
2650 
2651 // Do the work to create the function definition in addition to
2652 // parsing the body (compound_statement).
2653 //
2654 // If 'deferredTokens' are passed in, just get the token stream,
2655 // don't process.
2656 //
acceptFunctionDefinition(TFunctionDeclarator & declarator,TIntermNode * & nodeList,TVector<HlslToken> * deferredTokens)2657 bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2658                                            TVector<HlslToken>* deferredTokens)
2659 {
2660     parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
2661 
2662     if (deferredTokens)
2663         return captureBlockTokens(*deferredTokens);
2664     else
2665         return acceptFunctionBody(declarator, nodeList);
2666 }
2667 
acceptFunctionBody(TFunctionDeclarator & declarator,TIntermNode * & nodeList)2668 bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2669 {
2670     // we might get back an entry-point
2671     TIntermNode* entryPointNode = nullptr;
2672 
2673     // This does a pushScope()
2674     TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2675                                                                       declarator.attributes, entryPointNode);
2676 
2677     // compound_statement
2678     TIntermNode* functionBody = nullptr;
2679     if (! acceptCompoundStatement(functionBody))
2680         return false;
2681 
2682     // this does a popScope()
2683     parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
2684 
2685     // Hook up the 1 or 2 function definitions.
2686     nodeList = intermediate.growAggregate(nodeList, functionNode);
2687     nodeList = intermediate.growAggregate(nodeList, entryPointNode);
2688 
2689     return true;
2690 }
2691 
2692 // Accept an expression with parenthesis around it, where
2693 // the parenthesis ARE NOT expression parenthesis, but the
2694 // syntactically required ones like in "if ( expression )".
2695 //
2696 // Also accepts a declaration expression; "if (int a = expression)".
2697 //
2698 // Note this one is not set up to be speculative; as it gives
2699 // errors if not found.
2700 //
acceptParenExpression(TIntermTyped * & expression)2701 bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2702 {
2703     expression = nullptr;
2704 
2705     // LEFT_PAREN
2706     if (! acceptTokenClass(EHTokLeftParen))
2707         expected("(");
2708 
2709     bool decl = false;
2710     TIntermNode* declNode = nullptr;
2711     decl = acceptControlDeclaration(declNode);
2712     if (decl) {
2713         if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2714             expected("initialized declaration");
2715             return false;
2716         } else
2717             expression = declNode->getAsTyped();
2718     } else {
2719         // no declaration
2720         if (! acceptExpression(expression)) {
2721             expected("expression");
2722             return false;
2723         }
2724     }
2725 
2726     // RIGHT_PAREN
2727     if (! acceptTokenClass(EHTokRightParen))
2728         expected(")");
2729 
2730     return true;
2731 }
2732 
2733 // The top-level full expression recognizer.
2734 //
2735 // expression
2736 //      : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
2737 //
acceptExpression(TIntermTyped * & node)2738 bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2739 {
2740     node = nullptr;
2741 
2742     // assignment_expression
2743     if (! acceptAssignmentExpression(node))
2744         return false;
2745 
2746     if (! peekTokenClass(EHTokComma))
2747         return true;
2748 
2749     do {
2750         // ... COMMA
2751         TSourceLoc loc = token.loc;
2752         advanceToken();
2753 
2754         // ... assignment_expression
2755         TIntermTyped* rightNode = nullptr;
2756         if (! acceptAssignmentExpression(rightNode)) {
2757             expected("assignment expression");
2758             return false;
2759         }
2760 
2761         node = intermediate.addComma(node, rightNode, loc);
2762 
2763         if (! peekTokenClass(EHTokComma))
2764             return true;
2765     } while (true);
2766 }
2767 
2768 // initializer
2769 //      : LEFT_BRACE RIGHT_BRACE
2770 //      | LEFT_BRACE initializer_list RIGHT_BRACE
2771 //
2772 // initializer_list
2773 //      : assignment_expression COMMA assignment_expression COMMA ...
2774 //
acceptInitializer(TIntermTyped * & node)2775 bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2776 {
2777     // LEFT_BRACE
2778     if (! acceptTokenClass(EHTokLeftBrace))
2779         return false;
2780 
2781     // RIGHT_BRACE
2782     TSourceLoc loc = token.loc;
2783     if (acceptTokenClass(EHTokRightBrace)) {
2784         // a zero-length initializer list
2785         node = intermediate.makeAggregate(loc);
2786         return true;
2787     }
2788 
2789     // initializer_list
2790     node = nullptr;
2791     do {
2792         // assignment_expression
2793         TIntermTyped* expr;
2794         if (! acceptAssignmentExpression(expr)) {
2795             expected("assignment expression in initializer list");
2796             return false;
2797         }
2798 
2799         const bool firstNode = (node == nullptr);
2800 
2801         node = intermediate.growAggregate(node, expr, loc);
2802 
2803         // If every sub-node in the list has qualifier EvqConst, the returned node becomes
2804         // EvqConst.  Otherwise, it becomes EvqTemporary. That doesn't happen with e.g.
2805         // EvqIn or EvqPosition, since the collection isn't EvqPosition if all the members are.
2806         if (firstNode && expr->getQualifier().storage == EvqConst)
2807             node->getQualifier().storage = EvqConst;
2808         else if (expr->getQualifier().storage != EvqConst)
2809             node->getQualifier().storage = EvqTemporary;
2810 
2811         // COMMA
2812         if (acceptTokenClass(EHTokComma)) {
2813             if (acceptTokenClass(EHTokRightBrace))  // allow trailing comma
2814                 return true;
2815             continue;
2816         }
2817 
2818         // RIGHT_BRACE
2819         if (acceptTokenClass(EHTokRightBrace))
2820             return true;
2821 
2822         expected(", or }");
2823         return false;
2824     } while (true);
2825 }
2826 
2827 // Accept an assignment expression, where assignment operations
2828 // associate right-to-left.  That is, it is implicit, for example
2829 //
2830 //    a op (b op (c op d))
2831 //
2832 // assigment_expression
2833 //      : initializer
2834 //      | conditional_expression
2835 //      | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
2836 //
acceptAssignmentExpression(TIntermTyped * & node)2837 bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2838 {
2839     // initializer
2840     if (peekTokenClass(EHTokLeftBrace)) {
2841         if (acceptInitializer(node))
2842             return true;
2843 
2844         expected("initializer");
2845         return false;
2846     }
2847 
2848     // conditional_expression
2849     if (! acceptConditionalExpression(node))
2850         return false;
2851 
2852     // assignment operation?
2853     TOperator assignOp = HlslOpMap::assignment(peek());
2854     if (assignOp == EOpNull)
2855         return true;
2856 
2857     // assign_op
2858     TSourceLoc loc = token.loc;
2859     advanceToken();
2860 
2861     // conditional_expression assign_op conditional_expression ...
2862     // Done by recursing this function, which automatically
2863     // gets the right-to-left associativity.
2864     TIntermTyped* rightNode = nullptr;
2865     if (! acceptAssignmentExpression(rightNode)) {
2866         expected("assignment expression");
2867         return false;
2868     }
2869 
2870     node = parseContext.handleAssign(loc, assignOp, node, rightNode);
2871     node = parseContext.handleLvalue(loc, "assign", node);
2872 
2873     if (node == nullptr) {
2874         parseContext.error(loc, "could not create assignment", "", "");
2875         return false;
2876     }
2877 
2878     if (! peekTokenClass(EHTokComma))
2879         return true;
2880 
2881     return true;
2882 }
2883 
2884 // Accept a conditional expression, which associates right-to-left,
2885 // accomplished by the "true" expression calling down to lower
2886 // precedence levels than this level.
2887 //
2888 // conditional_expression
2889 //      : binary_expression
2890 //      | binary_expression QUESTION expression COLON assignment_expression
2891 //
acceptConditionalExpression(TIntermTyped * & node)2892 bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2893 {
2894     // binary_expression
2895     if (! acceptBinaryExpression(node, PlLogicalOr))
2896         return false;
2897 
2898     if (! acceptTokenClass(EHTokQuestion))
2899         return true;
2900 
2901     node = parseContext.convertConditionalExpression(token.loc, node, false);
2902     if (node == nullptr)
2903         return false;
2904 
2905     ++parseContext.controlFlowNestingLevel;  // this only needs to work right if no errors
2906 
2907     TIntermTyped* trueNode = nullptr;
2908     if (! acceptExpression(trueNode)) {
2909         expected("expression after ?");
2910         return false;
2911     }
2912     TSourceLoc loc = token.loc;
2913 
2914     if (! acceptTokenClass(EHTokColon)) {
2915         expected(":");
2916         return false;
2917     }
2918 
2919     TIntermTyped* falseNode = nullptr;
2920     if (! acceptAssignmentExpression(falseNode)) {
2921         expected("expression after :");
2922         return false;
2923     }
2924 
2925     --parseContext.controlFlowNestingLevel;
2926 
2927     node = intermediate.addSelection(node, trueNode, falseNode, loc);
2928 
2929     return true;
2930 }
2931 
2932 // Accept a binary expression, for binary operations that
2933 // associate left-to-right.  This is, it is implicit, for example
2934 //
2935 //    ((a op b) op c) op d
2936 //
2937 // binary_expression
2938 //      : expression op expression op expression ...
2939 //
2940 // where 'expression' is the next higher level in precedence.
2941 //
acceptBinaryExpression(TIntermTyped * & node,PrecedenceLevel precedenceLevel)2942 bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2943 {
2944     if (precedenceLevel > PlMul)
2945         return acceptUnaryExpression(node);
2946 
2947     // assignment_expression
2948     if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2949         return false;
2950 
2951     do {
2952         TOperator op = HlslOpMap::binary(peek());
2953         PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2954         if (tokenLevel < precedenceLevel)
2955             return true;
2956 
2957         // ... op
2958         TSourceLoc loc = token.loc;
2959         advanceToken();
2960 
2961         // ... expression
2962         TIntermTyped* rightNode = nullptr;
2963         if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2964             expected("expression");
2965             return false;
2966         }
2967 
2968         node = intermediate.addBinaryMath(op, node, rightNode, loc);
2969         if (node == nullptr) {
2970             parseContext.error(loc, "Could not perform requested binary operation", "", "");
2971             return false;
2972         }
2973     } while (true);
2974 }
2975 
2976 // unary_expression
2977 //      : (type) unary_expression
2978 //      | + unary_expression
2979 //      | - unary_expression
2980 //      | ! unary_expression
2981 //      | ~ unary_expression
2982 //      | ++ unary_expression
2983 //      | -- unary_expression
2984 //      | postfix_expression
2985 //
acceptUnaryExpression(TIntermTyped * & node)2986 bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2987 {
2988     // (type) unary_expression
2989     // Have to look two steps ahead, because this could be, e.g., a
2990     // postfix_expression instead, since that also starts with at "(".
2991     if (acceptTokenClass(EHTokLeftParen)) {
2992         TType castType;
2993         if (acceptType(castType)) {
2994             // recognize any array_specifier as part of the type
2995             TArraySizes* arraySizes = nullptr;
2996             acceptArraySpecifier(arraySizes);
2997             if (arraySizes != nullptr)
2998                 castType.transferArraySizes(arraySizes);
2999             TSourceLoc loc = token.loc;
3000             if (acceptTokenClass(EHTokRightParen)) {
3001                 // We've matched "(type)" now, get the expression to cast
3002                 if (! acceptUnaryExpression(node))
3003                     return false;
3004 
3005                 // Hook it up like a constructor
3006                 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
3007                 if (constructorFunction == nullptr) {
3008                     expected("type that can be constructed");
3009                     return false;
3010                 }
3011                 TIntermTyped* arguments = nullptr;
3012                 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
3013                 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
3014 
3015                 return node != nullptr;
3016             } else {
3017                 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
3018                 // the '(int' part.  We must back up twice.
3019                 recedeToken();
3020                 recedeToken();
3021 
3022                 // Note, there are no array constructors like
3023                 //   (float[2](...))
3024                 if (arraySizes != nullptr)
3025                     parseContext.error(loc, "parenthesized array constructor not allowed", "([]())", "", "");
3026             }
3027         } else {
3028             // This isn't a type cast, but it still started "(", so if it is a
3029             // unary expression, it can only be a postfix_expression, so try that.
3030             // Back it up first.
3031             recedeToken();
3032             return acceptPostfixExpression(node);
3033         }
3034     }
3035 
3036     // peek for "op unary_expression"
3037     TOperator unaryOp = HlslOpMap::preUnary(peek());
3038 
3039     // postfix_expression (if no unary operator)
3040     if (unaryOp == EOpNull)
3041         return acceptPostfixExpression(node);
3042 
3043     // op unary_expression
3044     TSourceLoc loc = token.loc;
3045     advanceToken();
3046     if (! acceptUnaryExpression(node))
3047         return false;
3048 
3049     // + is a no-op
3050     if (unaryOp == EOpAdd)
3051         return true;
3052 
3053     node = intermediate.addUnaryMath(unaryOp, node, loc);
3054 
3055     // These unary ops require lvalues
3056     if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
3057         node = parseContext.handleLvalue(loc, "unary operator", node);
3058 
3059     return node != nullptr;
3060 }
3061 
3062 // postfix_expression
3063 //      : LEFT_PAREN expression RIGHT_PAREN
3064 //      | literal
3065 //      | constructor
3066 //      | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
3067 //      | function_call
3068 //      | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
3069 //      | postfix_expression DOT IDENTIFIER
3070 //      | postfix_expression DOT IDENTIFIER arguments
3071 //      | postfix_expression arguments
3072 //      | postfix_expression INC_OP
3073 //      | postfix_expression DEC_OP
3074 //
acceptPostfixExpression(TIntermTyped * & node)3075 bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
3076 {
3077     // Not implemented as self-recursive:
3078     // The logical "right recursion" is done with a loop at the end
3079 
3080     // idToken will pick up either a variable or a function name in a function call
3081     HlslToken idToken;
3082 
3083     // Find something before the postfix operations, as they can't operate
3084     // on nothing.  So, no "return true", they fall through, only "return false".
3085     if (acceptTokenClass(EHTokLeftParen)) {
3086         // LEFT_PAREN expression RIGHT_PAREN
3087         if (! acceptExpression(node)) {
3088             expected("expression");
3089             return false;
3090         }
3091         if (! acceptTokenClass(EHTokRightParen)) {
3092             expected(")");
3093             return false;
3094         }
3095     } else if (acceptLiteral(node)) {
3096         // literal (nothing else to do yet)
3097     } else if (acceptConstructor(node)) {
3098         // constructor (nothing else to do yet)
3099     } else if (acceptIdentifier(idToken)) {
3100         // user-type, namespace name, variable, or function name
3101         TString* fullName = idToken.string;
3102         while (acceptTokenClass(EHTokColonColon)) {
3103             // user-type or namespace name
3104             fullName = NewPoolTString(fullName->c_str());
3105             fullName->append(parseContext.scopeMangler);
3106             if (acceptIdentifier(idToken))
3107                 fullName->append(*idToken.string);
3108             else {
3109                 expected("identifier after ::");
3110                 return false;
3111             }
3112         }
3113         if (! peekTokenClass(EHTokLeftParen)) {
3114             node = parseContext.handleVariable(idToken.loc, fullName);
3115             if (node == nullptr)
3116                 return false;
3117         } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
3118             // function_call (nothing else to do yet)
3119         } else {
3120             expected("function call arguments");
3121             return false;
3122         }
3123     } else {
3124         // nothing found, can't post operate
3125         return false;
3126     }
3127 
3128     // Something was found, chain as many postfix operations as exist.
3129     do {
3130         TSourceLoc loc = token.loc;
3131         TOperator postOp = HlslOpMap::postUnary(peek());
3132 
3133         // Consume only a valid post-unary operator, otherwise we are done.
3134         switch (postOp) {
3135         case EOpIndexDirectStruct:
3136         case EOpIndexIndirect:
3137         case EOpPostIncrement:
3138         case EOpPostDecrement:
3139         case EOpScoping:
3140             advanceToken();
3141             break;
3142         default:
3143             return true;
3144         }
3145 
3146         // We have a valid post-unary operator, process it.
3147         switch (postOp) {
3148         case EOpScoping:
3149         case EOpIndexDirectStruct:
3150         {
3151             // DOT IDENTIFIER
3152             // includes swizzles, member variables, and member functions
3153             HlslToken field;
3154             if (! acceptIdentifier(field)) {
3155                 expected("swizzle or member");
3156                 return false;
3157             }
3158 
3159             if (peekTokenClass(EHTokLeftParen)) {
3160                 // member function
3161                 TIntermTyped* thisNode = node;
3162 
3163                 // arguments
3164                 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
3165                     expected("function parameters");
3166                     return false;
3167                 }
3168             } else
3169                 node = parseContext.handleDotDereference(field.loc, node, *field.string);
3170 
3171             break;
3172         }
3173         case EOpIndexIndirect:
3174         {
3175             // LEFT_BRACKET integer_expression RIGHT_BRACKET
3176             TIntermTyped* indexNode = nullptr;
3177             if (! acceptExpression(indexNode) ||
3178                 ! peekTokenClass(EHTokRightBracket)) {
3179                 expected("expression followed by ']'");
3180                 return false;
3181             }
3182             advanceToken();
3183             node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
3184             if (node == nullptr)
3185                 return false;
3186             break;
3187         }
3188         case EOpPostIncrement:
3189             // INC_OP
3190             // fall through
3191         case EOpPostDecrement:
3192             // DEC_OP
3193             node = intermediate.addUnaryMath(postOp, node, loc);
3194             node = parseContext.handleLvalue(loc, "unary operator", node);
3195             break;
3196         default:
3197             assert(0);
3198             break;
3199         }
3200     } while (true);
3201 }
3202 
3203 // constructor
3204 //      : type argument_list
3205 //
acceptConstructor(TIntermTyped * & node)3206 bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
3207 {
3208     // type
3209     TType type;
3210     if (acceptType(type)) {
3211         TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
3212         if (constructorFunction == nullptr)
3213             return false;
3214 
3215         // arguments
3216         TIntermTyped* arguments = nullptr;
3217         if (! acceptArguments(constructorFunction, arguments)) {
3218             // It's possible this is a type keyword used as an identifier.  Put the token back
3219             // for later use.
3220             recedeToken();
3221             return false;
3222         }
3223 
3224         // hook it up
3225         node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
3226 
3227         return node != nullptr;
3228     }
3229 
3230     return false;
3231 }
3232 
3233 // The function_call identifier was already recognized, and passed in as idToken.
3234 //
3235 // function_call
3236 //      : [idToken] arguments
3237 //
acceptFunctionCall(const TSourceLoc & loc,TString & name,TIntermTyped * & node,TIntermTyped * baseObject)3238 bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
3239 {
3240     // name
3241     TString* functionName = nullptr;
3242     if (baseObject == nullptr) {
3243         functionName = &name;
3244     } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
3245         // Built-in methods are not in the symbol table as methods, but as global functions
3246         // taking an explicit 'this' as the first argument.
3247         functionName = NewPoolTString(BUILTIN_PREFIX);
3248         functionName->append(name);
3249     } else {
3250         if (! baseObject->getType().isStruct()) {
3251             expected("structure");
3252             return false;
3253         }
3254         functionName = NewPoolTString("");
3255         functionName->append(baseObject->getType().getTypeName());
3256         parseContext.addScopeMangler(*functionName);
3257         functionName->append(name);
3258     }
3259 
3260     // function
3261     TFunction* function = new TFunction(functionName, TType(EbtVoid));
3262 
3263     // arguments
3264     TIntermTyped* arguments = nullptr;
3265     if (baseObject != nullptr) {
3266         // Non-static member functions have an implicit first argument of the base object.
3267         parseContext.handleFunctionArgument(function, arguments, baseObject);
3268     }
3269     if (! acceptArguments(function, arguments))
3270         return false;
3271 
3272     // call
3273     node = parseContext.handleFunctionCall(loc, function, arguments);
3274 
3275     return node != nullptr;
3276 }
3277 
3278 // arguments
3279 //      : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
3280 //
3281 // The arguments are pushed onto the 'function' argument list and
3282 // onto the 'arguments' aggregate.
3283 //
acceptArguments(TFunction * function,TIntermTyped * & arguments)3284 bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
3285 {
3286     // LEFT_PAREN
3287     if (! acceptTokenClass(EHTokLeftParen))
3288         return false;
3289 
3290     // RIGHT_PAREN
3291     if (acceptTokenClass(EHTokRightParen))
3292         return true;
3293 
3294     // must now be at least one expression...
3295     do {
3296         // expression
3297         TIntermTyped* arg;
3298         if (! acceptAssignmentExpression(arg))
3299             return false;
3300 
3301         // hook it up
3302         parseContext.handleFunctionArgument(function, arguments, arg);
3303 
3304         // COMMA
3305         if (! acceptTokenClass(EHTokComma))
3306             break;
3307     } while (true);
3308 
3309     // RIGHT_PAREN
3310     if (! acceptTokenClass(EHTokRightParen)) {
3311         expected(")");
3312         return false;
3313     }
3314 
3315     return true;
3316 }
3317 
acceptLiteral(TIntermTyped * & node)3318 bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
3319 {
3320     switch (token.tokenClass) {
3321     case EHTokIntConstant:
3322         node = intermediate.addConstantUnion(token.i, token.loc, true);
3323         break;
3324     case EHTokUintConstant:
3325         node = intermediate.addConstantUnion(token.u, token.loc, true);
3326         break;
3327     case EHTokFloat16Constant:
3328         node = intermediate.addConstantUnion(token.d, EbtFloat16, token.loc, true);
3329         break;
3330     case EHTokFloatConstant:
3331         node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
3332         break;
3333     case EHTokDoubleConstant:
3334         node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
3335         break;
3336     case EHTokBoolConstant:
3337         node = intermediate.addConstantUnion(token.b, token.loc, true);
3338         break;
3339     case EHTokStringConstant:
3340         node = intermediate.addConstantUnion(token.string, token.loc, true);
3341         break;
3342 
3343     default:
3344         return false;
3345     }
3346 
3347     advanceToken();
3348 
3349     return true;
3350 }
3351 
3352 // simple_statement
3353 //      : SEMICOLON
3354 //      | declaration_statement
3355 //      | expression SEMICOLON
3356 //
acceptSimpleStatement(TIntermNode * & statement)3357 bool HlslGrammar::acceptSimpleStatement(TIntermNode*& statement)
3358 {
3359     // SEMICOLON
3360     if (acceptTokenClass(EHTokSemicolon))
3361         return true;
3362 
3363     // declaration
3364     if (acceptDeclaration(statement))
3365         return true;
3366 
3367     // expression
3368     TIntermTyped* node;
3369     if (acceptExpression(node))
3370         statement = node;
3371     else
3372         return false;
3373 
3374     // SEMICOLON (following an expression)
3375     if (acceptTokenClass(EHTokSemicolon))
3376         return true;
3377     else {
3378         expected(";");
3379         return false;
3380     }
3381 }
3382 
3383 // compound_statement
3384 //      : LEFT_CURLY statement statement ... RIGHT_CURLY
3385 //
acceptCompoundStatement(TIntermNode * & retStatement)3386 bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
3387 {
3388     TIntermAggregate* compoundStatement = nullptr;
3389 
3390     // LEFT_CURLY
3391     if (! acceptTokenClass(EHTokLeftBrace))
3392         return false;
3393 
3394     // statement statement ...
3395     TIntermNode* statement = nullptr;
3396     while (acceptStatement(statement)) {
3397         TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
3398         if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
3399                                   branch->getFlowOp() == EOpDefault)) {
3400             // hook up individual subsequences within a switch statement
3401             parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
3402             compoundStatement = nullptr;
3403         } else {
3404             // hook it up to the growing compound statement
3405             compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3406         }
3407     }
3408     if (compoundStatement)
3409         compoundStatement->setOperator(EOpSequence);
3410 
3411     retStatement = compoundStatement;
3412 
3413     // RIGHT_CURLY
3414     return acceptTokenClass(EHTokRightBrace);
3415 }
3416 
acceptScopedStatement(TIntermNode * & statement)3417 bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3418 {
3419     parseContext.pushScope();
3420     bool result = acceptStatement(statement);
3421     parseContext.popScope();
3422 
3423     return result;
3424 }
3425 
acceptScopedCompoundStatement(TIntermNode * & statement)3426 bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
3427 {
3428     parseContext.pushScope();
3429     bool result = acceptCompoundStatement(statement);
3430     parseContext.popScope();
3431 
3432     return result;
3433 }
3434 
3435 // statement
3436 //      : attributes attributed_statement
3437 //
3438 // attributed_statement
3439 //      : compound_statement
3440 //      | simple_statement
3441 //      | selection_statement
3442 //      | switch_statement
3443 //      | case_label
3444 //      | default_label
3445 //      | iteration_statement
3446 //      | jump_statement
3447 //
acceptStatement(TIntermNode * & statement)3448 bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3449 {
3450     statement = nullptr;
3451 
3452     // attributes
3453     TAttributes attributes;
3454     acceptAttributes(attributes);
3455 
3456     // attributed_statement
3457     switch (peek()) {
3458     case EHTokLeftBrace:
3459         return acceptScopedCompoundStatement(statement);
3460 
3461     case EHTokIf:
3462         return acceptSelectionStatement(statement, attributes);
3463 
3464     case EHTokSwitch:
3465         return acceptSwitchStatement(statement, attributes);
3466 
3467     case EHTokFor:
3468     case EHTokDo:
3469     case EHTokWhile:
3470         return acceptIterationStatement(statement, attributes);
3471 
3472     case EHTokContinue:
3473     case EHTokBreak:
3474     case EHTokDiscard:
3475     case EHTokReturn:
3476         return acceptJumpStatement(statement);
3477 
3478     case EHTokCase:
3479         return acceptCaseLabel(statement);
3480     case EHTokDefault:
3481         return acceptDefaultLabel(statement);
3482 
3483     case EHTokRightBrace:
3484         // Performance: not strictly necessary, but stops a bunch of hunting early,
3485         // and is how sequences of statements end.
3486         return false;
3487 
3488     default:
3489         return acceptSimpleStatement(statement);
3490     }
3491 
3492     return true;
3493 }
3494 
3495 // attributes
3496 //      : [zero or more:] bracketed-attribute
3497 //
3498 // bracketed-attribute:
3499 //      : LEFT_BRACKET scoped-attribute RIGHT_BRACKET
3500 //      : LEFT_BRACKET LEFT_BRACKET scoped-attribute RIGHT_BRACKET RIGHT_BRACKET
3501 //
3502 // scoped-attribute:
3503 //      : attribute
3504 //      | namespace COLON COLON attribute
3505 //
3506 // attribute:
3507 //      : UNROLL
3508 //      | UNROLL LEFT_PAREN literal RIGHT_PAREN
3509 //      | FASTOPT
3510 //      | ALLOW_UAV_CONDITION
3511 //      | BRANCH
3512 //      | FLATTEN
3513 //      | FORCECASE
3514 //      | CALL
3515 //      | DOMAIN
3516 //      | EARLYDEPTHSTENCIL
3517 //      | INSTANCE
3518 //      | MAXTESSFACTOR
3519 //      | OUTPUTCONTROLPOINTS
3520 //      | OUTPUTTOPOLOGY
3521 //      | PARTITIONING
3522 //      | PATCHCONSTANTFUNC
3523 //      | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
3524 //
acceptAttributes(TAttributes & attributes)3525 void HlslGrammar::acceptAttributes(TAttributes& attributes)
3526 {
3527     // For now, accept the [ XXX(X) ] syntax, but drop all but
3528     // numthreads, which is used to set the CS local size.
3529     // TODO: subset to correct set?  Pass on?
3530     do {
3531         HlslToken attributeToken;
3532 
3533         // LEFT_BRACKET?
3534         if (! acceptTokenClass(EHTokLeftBracket))
3535             return;
3536         // another LEFT_BRACKET?
3537         bool doubleBrackets = false;
3538         if (acceptTokenClass(EHTokLeftBracket))
3539             doubleBrackets = true;
3540 
3541         // attribute? (could be namespace; will adjust later)
3542         if (!acceptIdentifier(attributeToken)) {
3543             if (!peekTokenClass(EHTokRightBracket)) {
3544                 expected("namespace or attribute identifier");
3545                 advanceToken();
3546             }
3547         }
3548 
3549         TString nameSpace;
3550         if (acceptTokenClass(EHTokColonColon)) {
3551             // namespace COLON COLON
3552             nameSpace = *attributeToken.string;
3553             // attribute
3554             if (!acceptIdentifier(attributeToken)) {
3555                 expected("attribute identifier");
3556                 return;
3557             }
3558         }
3559 
3560         TIntermAggregate* expressions = nullptr;
3561 
3562         // (x, ...)
3563         if (acceptTokenClass(EHTokLeftParen)) {
3564             expressions = new TIntermAggregate;
3565 
3566             TIntermTyped* node;
3567             bool expectingExpression = false;
3568 
3569             while (acceptAssignmentExpression(node)) {
3570                 expectingExpression = false;
3571                 expressions->getSequence().push_back(node);
3572                 if (acceptTokenClass(EHTokComma))
3573                     expectingExpression = true;
3574             }
3575 
3576             // 'expressions' is an aggregate with the expressions in it
3577             if (! acceptTokenClass(EHTokRightParen))
3578                 expected(")");
3579 
3580             // Error for partial or missing expression
3581             if (expectingExpression || expressions->getSequence().empty())
3582                 expected("expression");
3583         }
3584 
3585         // RIGHT_BRACKET
3586         if (!acceptTokenClass(EHTokRightBracket)) {
3587             expected("]");
3588             return;
3589         }
3590         // another RIGHT_BRACKET?
3591         if (doubleBrackets && !acceptTokenClass(EHTokRightBracket)) {
3592             expected("]]");
3593             return;
3594         }
3595 
3596         // Add any values we found into the attribute map.
3597         if (attributeToken.string != nullptr) {
3598             TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string);
3599             if (attributeType == EatNone)
3600                 parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), "");
3601             else {
3602                 TAttributeArgs attributeArgs = { attributeType, expressions };
3603                 attributes.push_back(attributeArgs);
3604             }
3605         }
3606     } while (true);
3607 }
3608 
3609 // selection_statement
3610 //      : IF LEFT_PAREN expression RIGHT_PAREN statement
3611 //      : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3612 //
acceptSelectionStatement(TIntermNode * & statement,const TAttributes & attributes)3613 bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes)
3614 {
3615     TSourceLoc loc = token.loc;
3616 
3617     // IF
3618     if (! acceptTokenClass(EHTokIf))
3619         return false;
3620 
3621     // so that something declared in the condition is scoped to the lifetimes
3622     // of the then-else statements
3623     parseContext.pushScope();
3624 
3625     // LEFT_PAREN expression RIGHT_PAREN
3626     TIntermTyped* condition;
3627     if (! acceptParenExpression(condition))
3628         return false;
3629     condition = parseContext.convertConditionalExpression(loc, condition);
3630     if (condition == nullptr)
3631         return false;
3632 
3633     // create the child statements
3634     TIntermNodePair thenElse = { nullptr, nullptr };
3635 
3636     ++parseContext.controlFlowNestingLevel;  // this only needs to work right if no errors
3637 
3638     // then statement
3639     if (! acceptScopedStatement(thenElse.node1)) {
3640         expected("then statement");
3641         return false;
3642     }
3643 
3644     // ELSE
3645     if (acceptTokenClass(EHTokElse)) {
3646         // else statement
3647         if (! acceptScopedStatement(thenElse.node2)) {
3648             expected("else statement");
3649             return false;
3650         }
3651     }
3652 
3653     // Put the pieces together
3654     statement = intermediate.addSelection(condition, thenElse, loc);
3655     parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes);
3656 
3657     parseContext.popScope();
3658     --parseContext.controlFlowNestingLevel;
3659 
3660     return true;
3661 }
3662 
3663 // switch_statement
3664 //      : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3665 //
acceptSwitchStatement(TIntermNode * & statement,const TAttributes & attributes)3666 bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes)
3667 {
3668     // SWITCH
3669     TSourceLoc loc = token.loc;
3670 
3671     if (! acceptTokenClass(EHTokSwitch))
3672         return false;
3673 
3674     // LEFT_PAREN expression RIGHT_PAREN
3675     parseContext.pushScope();
3676     TIntermTyped* switchExpression;
3677     if (! acceptParenExpression(switchExpression)) {
3678         parseContext.popScope();
3679         return false;
3680     }
3681 
3682     // compound_statement
3683     parseContext.pushSwitchSequence(new TIntermSequence);
3684 
3685     ++parseContext.controlFlowNestingLevel;
3686     bool statementOkay = acceptCompoundStatement(statement);
3687     --parseContext.controlFlowNestingLevel;
3688 
3689     if (statementOkay)
3690         statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr,
3691                                            attributes);
3692 
3693     parseContext.popSwitchSequence();
3694     parseContext.popScope();
3695 
3696     return statementOkay;
3697 }
3698 
3699 // iteration_statement
3700 //      : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3701 //      | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3702 //      | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3703 //
3704 // Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
acceptIterationStatement(TIntermNode * & statement,const TAttributes & attributes)3705 bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
3706 {
3707     TSourceLoc loc = token.loc;
3708     TIntermTyped* condition = nullptr;
3709 
3710     EHlslTokenClass loop = peek();
3711     assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3712 
3713     //  WHILE or DO or FOR
3714     advanceToken();
3715 
3716     TIntermLoop* loopNode = nullptr;
3717     switch (loop) {
3718     case EHTokWhile:
3719         // so that something declared in the condition is scoped to the lifetime
3720         // of the while sub-statement
3721         parseContext.pushScope();  // this only needs to work right if no errors
3722         parseContext.nestLooping();
3723         ++parseContext.controlFlowNestingLevel;
3724 
3725         // LEFT_PAREN condition RIGHT_PAREN
3726         if (! acceptParenExpression(condition))
3727             return false;
3728         condition = parseContext.convertConditionalExpression(loc, condition);
3729         if (condition == nullptr)
3730             return false;
3731 
3732         // statement
3733         if (! acceptScopedStatement(statement)) {
3734             expected("while sub-statement");
3735             return false;
3736         }
3737 
3738         parseContext.unnestLooping();
3739         parseContext.popScope();
3740         --parseContext.controlFlowNestingLevel;
3741 
3742         loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
3743         statement = loopNode;
3744         break;
3745 
3746     case EHTokDo:
3747         parseContext.nestLooping();  // this only needs to work right if no errors
3748         ++parseContext.controlFlowNestingLevel;
3749 
3750         // statement
3751         if (! acceptScopedStatement(statement)) {
3752             expected("do sub-statement");
3753             return false;
3754         }
3755 
3756         // WHILE
3757         if (! acceptTokenClass(EHTokWhile)) {
3758             expected("while");
3759             return false;
3760         }
3761 
3762         // LEFT_PAREN condition RIGHT_PAREN
3763         if (! acceptParenExpression(condition))
3764             return false;
3765         condition = parseContext.convertConditionalExpression(loc, condition);
3766         if (condition == nullptr)
3767             return false;
3768 
3769         if (! acceptTokenClass(EHTokSemicolon))
3770             expected(";");
3771 
3772         parseContext.unnestLooping();
3773         --parseContext.controlFlowNestingLevel;
3774 
3775         loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
3776         statement = loopNode;
3777         break;
3778 
3779     case EHTokFor:
3780     {
3781         // LEFT_PAREN
3782         if (! acceptTokenClass(EHTokLeftParen))
3783             expected("(");
3784 
3785         // so that something declared in the condition is scoped to the lifetime
3786         // of the for sub-statement
3787         parseContext.pushScope();
3788 
3789         // initializer
3790         TIntermNode* initNode = nullptr;
3791         if (! acceptSimpleStatement(initNode))
3792             expected("for-loop initializer statement");
3793 
3794         parseContext.nestLooping();  // this only needs to work right if no errors
3795         ++parseContext.controlFlowNestingLevel;
3796 
3797         // condition SEMI_COLON
3798         acceptExpression(condition);
3799         if (! acceptTokenClass(EHTokSemicolon))
3800             expected(";");
3801         if (condition != nullptr) {
3802             condition = parseContext.convertConditionalExpression(loc, condition);
3803             if (condition == nullptr)
3804                 return false;
3805         }
3806 
3807         // iterator SEMI_COLON
3808         TIntermTyped* iterator = nullptr;
3809         acceptExpression(iterator);
3810         if (! acceptTokenClass(EHTokRightParen))
3811             expected(")");
3812 
3813         // statement
3814         if (! acceptScopedStatement(statement)) {
3815             expected("for sub-statement");
3816             return false;
3817         }
3818 
3819         statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode);
3820 
3821         parseContext.popScope();
3822         parseContext.unnestLooping();
3823         --parseContext.controlFlowNestingLevel;
3824 
3825         break;
3826     }
3827 
3828     default:
3829         return false;
3830     }
3831 
3832     parseContext.handleLoopAttributes(loc, loopNode, attributes);
3833     return true;
3834 }
3835 
3836 // jump_statement
3837 //      : CONTINUE SEMICOLON
3838 //      | BREAK SEMICOLON
3839 //      | DISCARD SEMICOLON
3840 //      | RETURN SEMICOLON
3841 //      | RETURN expression SEMICOLON
3842 //
acceptJumpStatement(TIntermNode * & statement)3843 bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3844 {
3845     EHlslTokenClass jump = peek();
3846     switch (jump) {
3847     case EHTokContinue:
3848     case EHTokBreak:
3849     case EHTokDiscard:
3850     case EHTokReturn:
3851         advanceToken();
3852         break;
3853     default:
3854         // not something we handle in this function
3855         return false;
3856     }
3857 
3858     switch (jump) {
3859     case EHTokContinue:
3860         statement = intermediate.addBranch(EOpContinue, token.loc);
3861         if (parseContext.loopNestingLevel == 0) {
3862             expected("loop");
3863             return false;
3864         }
3865         break;
3866     case EHTokBreak:
3867         statement = intermediate.addBranch(EOpBreak, token.loc);
3868         if (parseContext.loopNestingLevel == 0 && parseContext.switchSequenceStack.size() == 0) {
3869             expected("loop or switch");
3870             return false;
3871         }
3872         break;
3873     case EHTokDiscard:
3874         statement = intermediate.addBranch(EOpKill, token.loc);
3875         break;
3876 
3877     case EHTokReturn:
3878     {
3879         // expression
3880         TIntermTyped* node;
3881         if (acceptExpression(node)) {
3882             // hook it up
3883             statement = parseContext.handleReturnValue(token.loc, node);
3884         } else
3885             statement = intermediate.addBranch(EOpReturn, token.loc);
3886         break;
3887     }
3888 
3889     default:
3890         assert(0);
3891         return false;
3892     }
3893 
3894     // SEMICOLON
3895     if (! acceptTokenClass(EHTokSemicolon))
3896         expected(";");
3897 
3898     return true;
3899 }
3900 
3901 // case_label
3902 //      : CASE expression COLON
3903 //
acceptCaseLabel(TIntermNode * & statement)3904 bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3905 {
3906     TSourceLoc loc = token.loc;
3907     if (! acceptTokenClass(EHTokCase))
3908         return false;
3909 
3910     TIntermTyped* expression;
3911     if (! acceptExpression(expression)) {
3912         expected("case expression");
3913         return false;
3914     }
3915 
3916     if (! acceptTokenClass(EHTokColon)) {
3917         expected(":");
3918         return false;
3919     }
3920 
3921     statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3922 
3923     return true;
3924 }
3925 
3926 // default_label
3927 //      : DEFAULT COLON
3928 //
acceptDefaultLabel(TIntermNode * & statement)3929 bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3930 {
3931     TSourceLoc loc = token.loc;
3932     if (! acceptTokenClass(EHTokDefault))
3933         return false;
3934 
3935     if (! acceptTokenClass(EHTokColon)) {
3936         expected(":");
3937         return false;
3938     }
3939 
3940     statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3941 
3942     return true;
3943 }
3944 
3945 // array_specifier
3946 //      : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3947 //      : LEFT_BRACKET RGHT_BRACKET // optional
3948 //
acceptArraySpecifier(TArraySizes * & arraySizes)3949 void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3950 {
3951     arraySizes = nullptr;
3952 
3953     // Early-out if there aren't any array dimensions
3954     if (!peekTokenClass(EHTokLeftBracket))
3955         return;
3956 
3957     // If we get here, we have at least one array dimension.  This will track the sizes we find.
3958     arraySizes = new TArraySizes;
3959 
3960     // Collect each array dimension.
3961     while (acceptTokenClass(EHTokLeftBracket)) {
3962         TSourceLoc loc = token.loc;
3963         TIntermTyped* sizeExpr = nullptr;
3964 
3965         // Array sizing expression is optional.  If omitted, array will be later sized by initializer list.
3966         const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3967 
3968         if (! acceptTokenClass(EHTokRightBracket)) {
3969             expected("]");
3970             return;
3971         }
3972 
3973         if (hasArraySize) {
3974             TArraySize arraySize;
3975             parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3976             arraySizes->addInnerSize(arraySize);
3977         } else {
3978             arraySizes->addInnerSize(0);  // sized by initializers.
3979         }
3980     }
3981 }
3982 
3983 // post_decls
3984 //      : COLON semantic // optional
3985 //        COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3986 //        COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
3987 //        COLON LAYOUT layout_qualifier_list
3988 //        annotations // optional
3989 //
3990 // Return true if any tokens were accepted. That is,
3991 // false can be returned on successfully recognizing nothing,
3992 // not necessarily meaning bad syntax.
3993 //
acceptPostDecls(TQualifier & qualifier)3994 bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
3995 {
3996     bool found = false;
3997 
3998     do {
3999         // COLON
4000         if (acceptTokenClass(EHTokColon)) {
4001             found = true;
4002             HlslToken idToken;
4003             if (peekTokenClass(EHTokLayout))
4004                 acceptLayoutQualifierList(qualifier);
4005             else if (acceptTokenClass(EHTokPackOffset)) {
4006                 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
4007                 if (! acceptTokenClass(EHTokLeftParen)) {
4008                     expected("(");
4009                     return false;
4010                 }
4011                 HlslToken locationToken;
4012                 if (! acceptIdentifier(locationToken)) {
4013                     expected("c[subcomponent][.component]");
4014                     return false;
4015                 }
4016                 HlslToken componentToken;
4017                 if (acceptTokenClass(EHTokDot)) {
4018                     if (! acceptIdentifier(componentToken)) {
4019                         expected("component");
4020                         return false;
4021                     }
4022                 }
4023                 if (! acceptTokenClass(EHTokRightParen)) {
4024                     expected(")");
4025                     break;
4026                 }
4027                 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
4028             } else if (! acceptIdentifier(idToken)) {
4029                 expected("layout, semantic, packoffset, or register");
4030                 return false;
4031             } else if (*idToken.string == "register") {
4032                 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
4033                 // LEFT_PAREN
4034                 if (! acceptTokenClass(EHTokLeftParen)) {
4035                     expected("(");
4036                     return false;
4037                 }
4038                 HlslToken registerDesc;  // for Type#
4039                 HlslToken profile;
4040                 if (! acceptIdentifier(registerDesc)) {
4041                     expected("register number description");
4042                     return false;
4043                 }
4044                 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
4045                                                        acceptTokenClass(EHTokComma)) {
4046                     // Then we didn't really see the registerDesc yet, it was
4047                     // actually the profile.  Adjust...
4048                     profile = registerDesc;
4049                     if (! acceptIdentifier(registerDesc)) {
4050                         expected("register number description");
4051                         return false;
4052                     }
4053                 }
4054                 int subComponent = 0;
4055                 if (acceptTokenClass(EHTokLeftBracket)) {
4056                     // LEFT_BRACKET subcomponent RIGHT_BRACKET
4057                     if (! peekTokenClass(EHTokIntConstant)) {
4058                         expected("literal integer");
4059                         return false;
4060                     }
4061                     subComponent = token.i;
4062                     advanceToken();
4063                     if (! acceptTokenClass(EHTokRightBracket)) {
4064                         expected("]");
4065                         break;
4066                     }
4067                 }
4068                 // (COMMA SPACEN)opt
4069                 HlslToken spaceDesc;
4070                 if (acceptTokenClass(EHTokComma)) {
4071                     if (! acceptIdentifier(spaceDesc)) {
4072                         expected ("space identifier");
4073                         return false;
4074                     }
4075                 }
4076                 // RIGHT_PAREN
4077                 if (! acceptTokenClass(EHTokRightParen)) {
4078                     expected(")");
4079                     break;
4080                 }
4081                 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
4082             } else {
4083                 // semantic, in idToken.string
4084                 TString semanticUpperCase = *idToken.string;
4085                 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
4086                 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
4087             }
4088         } else if (peekTokenClass(EHTokLeftAngle)) {
4089             found = true;
4090             acceptAnnotations(qualifier);
4091         } else
4092             break;
4093 
4094     } while (true);
4095 
4096     return found;
4097 }
4098 
4099 //
4100 // Get the stream of tokens from the scanner, but skip all syntactic/semantic
4101 // processing.
4102 //
captureBlockTokens(TVector<HlslToken> & tokens)4103 bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
4104 {
4105     if (! peekTokenClass(EHTokLeftBrace))
4106         return false;
4107 
4108     int braceCount = 0;
4109 
4110     do {
4111         switch (peek()) {
4112         case EHTokLeftBrace:
4113             ++braceCount;
4114             break;
4115         case EHTokRightBrace:
4116             --braceCount;
4117             break;
4118         case EHTokNone:
4119             // End of input before balance { } is bad...
4120             return false;
4121         default:
4122             break;
4123         }
4124 
4125         tokens.push_back(token);
4126         advanceToken();
4127     } while (braceCount > 0);
4128 
4129     return true;
4130 }
4131 
4132 // Return a string for just the types that can also be declared as an identifier.
getTypeString(EHlslTokenClass tokenClass) const4133 const char* HlslGrammar::getTypeString(EHlslTokenClass tokenClass) const
4134 {
4135     switch (tokenClass) {
4136     case EHTokSample:     return "sample";
4137     case EHTokHalf:       return "half";
4138     case EHTokHalf1x1:    return "half1x1";
4139     case EHTokHalf1x2:    return "half1x2";
4140     case EHTokHalf1x3:    return "half1x3";
4141     case EHTokHalf1x4:    return "half1x4";
4142     case EHTokHalf2x1:    return "half2x1";
4143     case EHTokHalf2x2:    return "half2x2";
4144     case EHTokHalf2x3:    return "half2x3";
4145     case EHTokHalf2x4:    return "half2x4";
4146     case EHTokHalf3x1:    return "half3x1";
4147     case EHTokHalf3x2:    return "half3x2";
4148     case EHTokHalf3x3:    return "half3x3";
4149     case EHTokHalf3x4:    return "half3x4";
4150     case EHTokHalf4x1:    return "half4x1";
4151     case EHTokHalf4x2:    return "half4x2";
4152     case EHTokHalf4x3:    return "half4x3";
4153     case EHTokHalf4x4:    return "half4x4";
4154     case EHTokBool:       return "bool";
4155     case EHTokFloat:      return "float";
4156     case EHTokDouble:     return "double";
4157     case EHTokInt:        return "int";
4158     case EHTokUint:       return "uint";
4159     case EHTokMin16float: return "min16float";
4160     case EHTokMin10float: return "min10float";
4161     case EHTokMin16int:   return "min16int";
4162     case EHTokMin12int:   return "min12int";
4163     case EHTokConstantBuffer: return "ConstantBuffer";
4164     case EHTokLayout:     return "layout";
4165     default:
4166         return nullptr;
4167     }
4168 }
4169 
4170 } // end namespace glslang
4171