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