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