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