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