blob: b5dfdddd3c34d7b8934c4dc18fb74fe1ba5004e8 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
2//Copyright (C) 2016 Google, Inc.
LoopDawg6daaa4f2016-06-23 19:13:48 -06003//Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
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
John Kessenichd016be12016-03-13 11:24:20 -060037//
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,
John Kessenich078d7f22016-03-14 10:02:11 -060046// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060047// 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
John Kesseniche01a9bc2016-03-12 20:11:22 -070054#include "hlslTokens.h"
55#include "hlslGrammar.h"
steve-lunarg1868b142016-10-20 13:07:10 -060056#include "hlslAttributes.h"
John Kesseniche01a9bc2016-03-12 20:11:22 -070057
58namespace glslang {
59
60// Root entry point to this recursive decent parser.
61// Return true if compilation unit was successfully accepted.
62bool HlslGrammar::parse()
63{
64 advanceToken();
65 return acceptCompilationUnit();
66}
67
68void HlslGrammar::expected(const char* syntax)
69{
70 parseContext.error(token.loc, "Expected", syntax, "");
71}
72
LoopDawg4886f692016-06-29 10:58:58 -060073void HlslGrammar::unimplemented(const char* error)
74{
75 parseContext.error(token.loc, "Unimplemented", error, "");
76}
77
John Kessenichaecd4972016-03-14 10:46:34 -060078// Only process the next token if it is an identifier.
79// Return true if it was an identifier.
80bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
81{
82 if (peekTokenClass(EHTokIdentifier)) {
83 idToken = token;
84 advanceToken();
85 return true;
86 }
87
steve-lunarg5ca85ad2016-12-26 18:45:52 -070088 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
89 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
90 // valid identifier, nor is "linear". This code special cases the known instances of this, so
91 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
92
93 TString* idString = nullptr;
94 switch (peek()) {
95 case EHTokSample: idString = NewPoolTString("sample"); break;
96 case EHTokHalf: idString = NewPoolTString("half"); break;
97 case EHTokBool: idString = NewPoolTString("bool"); break;
98 case EHTokFloat: idString = NewPoolTString("float"); break;
99 case EHTokDouble: idString = NewPoolTString("double"); break;
100 case EHTokInt: idString = NewPoolTString("int"); break;
101 case EHTokUint: idString = NewPoolTString("uint"); break;
102 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
103 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
104 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
105 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
106 default:
107 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700108 }
109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 token.string = idString;
111 token.tokenClass = EHTokIdentifier;
112 token.symbol = nullptr;
113 idToken = token;
114
115 advanceToken();
116
117 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600118}
119
John Kesseniche01a9bc2016-03-12 20:11:22 -0700120// compilationUnit
121// : list of externalDeclaration
steve-lunargcb88de52016-08-03 07:04:18 -0600122// | SEMICOLONS
John Kesseniche01a9bc2016-03-12 20:11:22 -0700123//
124bool HlslGrammar::acceptCompilationUnit()
125{
John Kessenichd016be12016-03-13 11:24:20 -0600126 TIntermNode* unitNode = nullptr;
127
John Kessenich9c86c6a2016-05-03 22:49:24 -0600128 while (! peekTokenClass(EHTokNone)) {
steve-lunargcb88de52016-08-03 07:04:18 -0600129 // HLSL allows semicolons between global declarations, e.g, between functions.
130 if (acceptTokenClass(EHTokSemicolon))
131 continue;
132
John Kessenichd016be12016-03-13 11:24:20 -0600133 // externalDeclaration
134 TIntermNode* declarationNode;
135 if (! acceptDeclaration(declarationNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136 return false;
John Kessenichd016be12016-03-13 11:24:20 -0600137
138 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600139 unitNode = intermediate.growAggregate(unitNode, declarationNode);
John Kesseniche01a9bc2016-03-12 20:11:22 -0700140 }
141
John Kessenichd016be12016-03-13 11:24:20 -0600142 // set root of AST
John Kessenich078d7f22016-03-14 10:02:11 -0600143 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600144
John Kesseniche01a9bc2016-03-12 20:11:22 -0700145 return true;
146}
147
LoopDawg4886f692016-06-29 10:58:58 -0600148// sampler_state
149// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
150//
151// sampler_state_assignment
152// : sampler_state_identifier EQUAL value SEMICOLON
153//
154// sampler_state_identifier
155// : ADDRESSU
156// | ADDRESSV
157// | ADDRESSW
158// | BORDERCOLOR
159// | FILTER
160// | MAXANISOTROPY
161// | MAXLOD
162// | MINLOD
163// | MIPLODBIAS
164//
165bool HlslGrammar::acceptSamplerState()
166{
167 // TODO: this should be genericized to accept a list of valid tokens and
168 // return token/value pairs. Presently it is specific to texture values.
169
170 if (! acceptTokenClass(EHTokLeftBrace))
171 return true;
172
173 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
174
175 do {
176 // read state name
177 HlslToken state;
178 if (! acceptIdentifier(state))
179 break; // end of list
180
181 // FXC accepts any case
182 TString stateName = *state.string;
183 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
184
185 if (! acceptTokenClass(EHTokAssign)) {
186 expected("assign");
187 return false;
188 }
189
190 if (stateName == "minlod" || stateName == "maxlod") {
191 if (! peekTokenClass(EHTokIntConstant)) {
192 expected("integer");
193 return false;
194 }
195
196 TIntermTyped* lod = nullptr;
197 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
198 return false;
199 } else if (stateName == "maxanisotropy") {
200 if (! peekTokenClass(EHTokIntConstant)) {
201 expected("integer");
202 return false;
203 }
204
205 TIntermTyped* maxAnisotropy = nullptr;
206 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
207 return false;
208 } else if (stateName == "filter") {
209 HlslToken filterMode;
210 if (! acceptIdentifier(filterMode)) {
211 expected("filter mode");
212 return false;
213 }
214 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
215 HlslToken addrMode;
216 if (! acceptIdentifier(addrMode)) {
217 expected("texture address mode");
218 return false;
219 }
220 } else if (stateName == "miplodbias") {
221 TIntermTyped* lodBias = nullptr;
222 if (! acceptLiteral(lodBias)) {
223 expected("lod bias");
224 return false;
225 }
226 } else if (stateName == "bordercolor") {
227 return false;
228 } else {
229 expected("texture state");
230 return false;
231 }
232
233 // SEMICOLON
234 if (! acceptTokenClass(EHTokSemicolon)) {
235 expected("semicolon");
236 return false;
237 }
238 } while (true);
239
240 if (! acceptTokenClass(EHTokRightBrace))
241 return false;
242
243 return true;
244}
245
246// sampler_declaration_dx9
247// : SAMPLER identifier EQUAL sampler_type sampler_state
248//
John Kesseniche4821e42016-07-16 10:19:43 -0600249bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600250{
251 if (! acceptTokenClass(EHTokSampler))
252 return false;
253
254 // TODO: remove this when DX9 style declarations are implemented.
255 unimplemented("Direct3D 9 sampler declaration");
256
257 // read sampler name
258 HlslToken name;
259 if (! acceptIdentifier(name)) {
260 expected("sampler name");
261 return false;
262 }
263
264 if (! acceptTokenClass(EHTokAssign)) {
265 expected("=");
266 return false;
267 }
268
269 return false;
270}
271
272
John Kesseniche01a9bc2016-03-12 20:11:22 -0700273// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600274// : sampler_declaration_dx9 post_decls SEMICOLON
275// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600276// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600277// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600278// | typedef declaration
John Kessenich87142c72016-03-12 20:24:24 -0700279//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600280// declarator_list
281// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600282//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600283// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600284// : identifier array_specifier post_decls
285// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600286// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600287//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600288// Parsing has to go pretty far in to know whether it's a variable, prototype, or
289// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600290// as above. (The 'identifier' in the first item in init_declarator list is the
291// same as 'identifier' for function declarations.)
292//
293// 'node' could get populated if the declaration creates code, like an initializer
John Kessenichd016be12016-03-13 11:24:20 -0600294// or a function body.
295//
296bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700297{
John Kessenichd016be12016-03-13 11:24:20 -0600298 node = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600299 bool list = false;
John Kessenichd016be12016-03-13 11:24:20 -0600300
steve-lunarg1868b142016-10-20 13:07:10 -0600301 // attributes
302 TAttributeMap attributes;
303 acceptAttributes(attributes);
304
John Kessenich5e69ec62016-07-05 00:02:40 -0600305 // typedef
306 bool typedefDecl = acceptTokenClass(EHTokTypedef);
307
John Kesseniche82061d2016-09-27 14:38:57 -0600308 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600309
310 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600311 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
312 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
313 // HLSL shaders, this will have to be a master level switch
314 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
315 // For that reason, this line is commented out
Dan Bakerc7e50162016-08-05 14:52:38 -0400316
John Kesseniche82061d2016-09-27 14:38:57 -0600317 // if (acceptSamplerDeclarationDX9(declaredType))
Dan Bakerc7e50162016-08-05 14:52:38 -0400318 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600319
320 // fully_specified_type
John Kesseniche82061d2016-09-27 14:38:57 -0600321 if (! acceptFullySpecifiedType(declaredType))
John Kessenich87142c72016-03-12 20:24:24 -0700322 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600323
John Kessenich87142c72016-03-12 20:24:24 -0700324 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600325 HlslToken idToken;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600326 while (acceptIdentifier(idToken)) {
steve-lunargf1e0c872016-10-31 15:13:43 -0600327 TString* fnName = idToken.string;
328
329 // Potentially rename shader entry point function. No-op most of the time.
330 parseContext.renameShaderFunction(fnName);
331
John Kessenich5f934b02016-03-13 17:58:25 -0600332 // function_parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600333 TFunction& function = *new TFunction(fnName, declaredType);
John Kessenich9e079532016-09-02 20:05:19 -0600334 if (acceptFunctionParameters(function)) {
John Kessenich630dd7d2016-06-12 23:52:12 -0600335 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -0600336 acceptPostDecls(function.getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600337
John Kessenichd5ed0b62016-07-04 17:32:45 -0600338 // compound_statement (function body definition) or just a prototype?
339 if (peekTokenClass(EHTokLeftBrace)) {
340 if (list)
341 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600342 if (typedefDecl)
343 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
steve-lunarg1868b142016-10-20 13:07:10 -0600344 return acceptFunctionDefinition(function, node, attributes);
John Kessenich5e69ec62016-07-05 00:02:40 -0600345 } else {
346 if (typedefDecl)
347 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich9e079532016-09-02 20:05:19 -0600348 parseContext.handleFunctionDeclarator(idToken.loc, function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600349 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600350 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600351 // A variable declaration. Fix the storage qualifier if it's a global.
352 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
353 declaredType.getQualifier().storage = EvqUniform;
354
John Kesseniche82061d2016-09-27 14:38:57 -0600355 // We can handle multiple variables per type declaration, so
356 // the number of types can expand when arrayness is different.
357 TType variableType;
358 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600359
John Kesseniche82061d2016-09-27 14:38:57 -0600360 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600361 TArraySizes* arraySizes = nullptr;
362 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600363
John Kesseniche82061d2016-09-27 14:38:57 -0600364 // Fix arrayness in the variableType
365 if (declaredType.isImplicitlySizedArray()) {
366 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
367 // of different sizes, for this case sharing the shallow copy of arrayness
368 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
369 variableType.newArraySizes(declaredType.getArraySizes());
370 }
371 if (arraySizes || variableType.isArray()) {
372 // In the most general case, arrayness is potentially coming both from the
373 // declared type and from the variable: "int[] a[];" or just one or the other.
374 // Merge it all to the variableType, so all arrayness is part of the variableType.
375 parseContext.arrayDimMerge(variableType, arraySizes);
376 }
377
LoopDawg4886f692016-06-29 10:58:58 -0600378 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600379 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600380 if (! acceptSamplerState())
381 return false;
382 }
383
John Kessenichd5ed0b62016-07-04 17:32:45 -0600384 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600385 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600386
387 // EQUAL assignment_expression
388 TIntermTyped* expressionNode = nullptr;
389 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600390 if (typedefDecl)
391 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 if (! acceptAssignmentExpression(expressionNode)) {
393 expected("initializer");
394 return false;
395 }
396 }
397
John Kessenich6dbc0a72016-09-27 19:13:05 -0600398 // Hand off the actual declaration
399
400 // TODO: things scoped within an annotation need their own name space;
401 // TODO: strings are not yet handled.
402 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
403 if (typedefDecl)
404 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
405 else if (variableType.getBasicType() == EbtBlock)
406 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
407 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700408 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600409 // this isn't really an individual variable, but a member of the $Global buffer
410 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
411 } else {
412 // Declare the variable and add any initializer code to the AST.
413 // The top-level node is always made into an aggregate, as that's
414 // historically how the AST has been.
415 node = intermediate.growAggregate(node,
416 parseContext.declareVariable(idToken.loc, *idToken.string, variableType,
417 expressionNode),
418 idToken.loc);
419 }
420 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600421 }
John Kessenich5f934b02016-03-13 17:58:25 -0600422 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600423
424 if (acceptTokenClass(EHTokComma)) {
425 list = true;
426 continue;
427 }
428 };
429
430 // The top-level node is a sequence.
431 if (node != nullptr)
432 node->getAsAggregate()->setOperator(EOpSequence);
John Kessenich87142c72016-03-12 20:24:24 -0700433
John Kessenich078d7f22016-03-14 10:02:11 -0600434 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600435 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700436 // This may have been a false detection of what appeared to be a declaration, but
437 // was actually an assignment such as "float = 4", where "float" is an identifier.
438 // We put the token back to let further parsing happen for cases where that may
439 // happen. This errors on the side of caution, and mostly triggers the error.
440
441 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
442 recedeToken();
443 else
444 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600445 return false;
446 }
447
John Kesseniche01a9bc2016-03-12 20:11:22 -0700448 return true;
449}
450
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600451// control_declaration
452// : fully_specified_type identifier EQUAL expression
453//
454bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
455{
456 node = nullptr;
457
458 // fully_specified_type
459 TType type;
460 if (! acceptFullySpecifiedType(type))
461 return false;
462
463 // identifier
464 HlslToken idToken;
465 if (! acceptIdentifier(idToken)) {
466 expected("identifier");
467 return false;
468 }
469
470 // EQUAL
471 TIntermTyped* expressionNode = nullptr;
472 if (! acceptTokenClass(EHTokAssign)) {
473 expected("=");
474 return false;
475 }
476
477 // expression
478 if (! acceptExpression(expressionNode)) {
479 expected("initializer");
480 return false;
481 }
482
John Kesseniche82061d2016-09-27 14:38:57 -0600483 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600484
485 return true;
486}
487
John Kessenich87142c72016-03-12 20:24:24 -0700488// fully_specified_type
489// : type_specifier
490// | type_qualifier type_specifier
491//
492bool HlslGrammar::acceptFullySpecifiedType(TType& type)
493{
494 // type_qualifier
495 TQualifier qualifier;
496 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600497 if (! acceptQualifier(qualifier))
498 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600499 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700500
501 // type_specifier
steve-lunarga64ed3e2016-12-18 17:51:14 -0700502 if (! acceptType(type)) {
503 // If this is not a type, we may have inadvertently gone down a wrong path
504 // py parsing "sample", which can be treated like either an identifier or a
505 // qualifier. Back it out, if we did.
506 if (qualifier.sample)
507 recedeToken();
508
John Kessenich87142c72016-03-12 20:24:24 -0700509 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700510 }
John Kessenich3d157c52016-07-25 16:05:33 -0600511 if (type.getBasicType() == EbtBlock) {
512 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600513 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600514 // further, it can create an anonymous instance of the block
515 if (peekTokenClass(EHTokSemicolon))
516 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600517 } else {
518 // Some qualifiers are set when parsing the type. Merge those with
519 // whatever comes from acceptQualifier.
520 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700521
steve-lunargbb0183f2016-10-04 16:58:14 -0600522 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600523 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700524
525 if (type.getQualifier().storage == EvqVaryingOut)
526 qualifier.storage = type.getQualifier().storage;
527
528 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600529 }
John Kessenich87142c72016-03-12 20:24:24 -0700530
531 return true;
532}
533
John Kessenich630dd7d2016-06-12 23:52:12 -0600534// type_qualifier
535// : qualifier qualifier ...
536//
537// Zero or more of these, so this can't return false.
538//
John Kessenichb9e39122016-08-17 10:22:08 -0600539bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700540{
John Kessenich630dd7d2016-06-12 23:52:12 -0600541 do {
542 switch (peek()) {
543 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600544 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600545 break;
546 case EHTokExtern:
547 // TODO: no meaning in glslang?
548 break;
549 case EHTokShared:
550 // TODO: hint
551 break;
552 case EHTokGroupShared:
553 qualifier.storage = EvqShared;
554 break;
555 case EHTokUniform:
556 qualifier.storage = EvqUniform;
557 break;
558 case EHTokConst:
559 qualifier.storage = EvqConst;
560 break;
561 case EHTokVolatile:
562 qualifier.volatil = true;
563 break;
564 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600565 qualifier.smooth = true;
566 break;
567 case EHTokCentroid:
568 qualifier.centroid = true;
569 break;
570 case EHTokNointerpolation:
571 qualifier.flat = true;
572 break;
573 case EHTokNoperspective:
574 qualifier.nopersp = true;
575 break;
576 case EHTokSample:
577 qualifier.sample = true;
578 break;
579 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600580 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600581 break;
582 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600583 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600584 break;
585 case EHTokPrecise:
586 qualifier.noContraction = true;
587 break;
LoopDawg9249c702016-07-12 20:44:32 -0600588 case EHTokIn:
589 qualifier.storage = EvqIn;
590 break;
591 case EHTokOut:
592 qualifier.storage = EvqOut;
593 break;
594 case EHTokInOut:
595 qualifier.storage = EvqInOut;
596 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600597 case EHTokLayout:
598 if (! acceptLayoutQualifierList(qualifier))
599 return false;
600 continue;
steve-lunargf49cdf42016-11-17 15:04:20 -0700601
602 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
603 // for output variables.
604 case EHTokPoint:
605 qualifier.storage = EvqIn;
606 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
607 return false;
608 break;
609 case EHTokLine:
610 qualifier.storage = EvqIn;
611 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
612 return false;
613 break;
614 case EHTokTriangle:
615 qualifier.storage = EvqIn;
616 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
617 return false;
618 break;
619 case EHTokLineAdj:
620 qualifier.storage = EvqIn;
621 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
622 return false;
623 break;
624 case EHTokTriangleAdj:
625 qualifier.storage = EvqIn;
626 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
627 return false;
628 break;
629
John Kessenich630dd7d2016-06-12 23:52:12 -0600630 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600631 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600632 }
633 advanceToken();
634 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700635}
636
John Kessenichb9e39122016-08-17 10:22:08 -0600637// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600638// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600639//
640// layout_qualifier
641// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600642// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600643//
644// Zero or more of these, so this can't return false.
645//
646bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
647{
648 if (! acceptTokenClass(EHTokLayout))
649 return false;
650
651 // LEFT_PAREN
652 if (! acceptTokenClass(EHTokLeftParen))
653 return false;
654
655 do {
656 // identifier
657 HlslToken idToken;
658 if (! acceptIdentifier(idToken))
659 break;
660
661 // EQUAL expression
662 if (acceptTokenClass(EHTokAssign)) {
663 TIntermTyped* expr;
664 if (! acceptConditionalExpression(expr)) {
665 expected("expression");
666 return false;
667 }
668 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
669 } else
670 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
671
672 // COMMA
673 if (! acceptTokenClass(EHTokComma))
674 break;
675 } while (true);
676
677 // RIGHT_PAREN
678 if (! acceptTokenClass(EHTokRightParen)) {
679 expected(")");
680 return false;
681 }
682
683 return true;
684}
685
LoopDawg6daaa4f2016-06-23 19:13:48 -0600686// template_type
687// : FLOAT
688// | DOUBLE
689// | INT
690// | DWORD
691// | UINT
692// | BOOL
693//
steve-lunargf49cdf42016-11-17 15:04:20 -0700694bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600695{
696 switch (peek()) {
697 case EHTokFloat:
698 basicType = EbtFloat;
699 break;
700 case EHTokDouble:
701 basicType = EbtDouble;
702 break;
703 case EHTokInt:
704 case EHTokDword:
705 basicType = EbtInt;
706 break;
707 case EHTokUint:
708 basicType = EbtUint;
709 break;
710 case EHTokBool:
711 basicType = EbtBool;
712 break;
713 default:
714 return false;
715 }
716
717 advanceToken();
718
719 return true;
720}
721
722// vector_template_type
723// : VECTOR
724// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
725//
726bool HlslGrammar::acceptVectorTemplateType(TType& type)
727{
728 if (! acceptTokenClass(EHTokVector))
729 return false;
730
731 if (! acceptTokenClass(EHTokLeftAngle)) {
732 // in HLSL, 'vector' alone means float4.
733 new(&type) TType(EbtFloat, EvqTemporary, 4);
734 return true;
735 }
736
737 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700738 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600739 expected("scalar type");
740 return false;
741 }
742
743 // COMMA
744 if (! acceptTokenClass(EHTokComma)) {
745 expected(",");
746 return false;
747 }
748
749 // integer
750 if (! peekTokenClass(EHTokIntConstant)) {
751 expected("literal integer");
752 return false;
753 }
754
755 TIntermTyped* vecSize;
756 if (! acceptLiteral(vecSize))
757 return false;
758
759 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
760
761 new(&type) TType(basicType, EvqTemporary, vecSizeI);
762
763 if (vecSizeI == 1)
764 type.makeVector();
765
766 if (!acceptTokenClass(EHTokRightAngle)) {
767 expected("right angle bracket");
768 return false;
769 }
770
771 return true;
772}
773
774// matrix_template_type
775// : MATRIX
776// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
777//
778bool HlslGrammar::acceptMatrixTemplateType(TType& type)
779{
780 if (! acceptTokenClass(EHTokMatrix))
781 return false;
782
783 if (! acceptTokenClass(EHTokLeftAngle)) {
784 // in HLSL, 'matrix' alone means float4x4.
785 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
786 return true;
787 }
788
789 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700790 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600791 expected("scalar type");
792 return false;
793 }
794
795 // COMMA
796 if (! acceptTokenClass(EHTokComma)) {
797 expected(",");
798 return false;
799 }
800
801 // integer rows
802 if (! peekTokenClass(EHTokIntConstant)) {
803 expected("literal integer");
804 return false;
805 }
806
807 TIntermTyped* rows;
808 if (! acceptLiteral(rows))
809 return false;
810
811 // COMMA
812 if (! acceptTokenClass(EHTokComma)) {
813 expected(",");
814 return false;
815 }
816
817 // integer cols
818 if (! peekTokenClass(EHTokIntConstant)) {
819 expected("literal integer");
820 return false;
821 }
822
823 TIntermTyped* cols;
824 if (! acceptLiteral(cols))
825 return false;
826
827 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600828 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
829 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600830
831 if (!acceptTokenClass(EHTokRightAngle)) {
832 expected("right angle bracket");
833 return false;
834 }
835
836 return true;
837}
838
steve-lunargf49cdf42016-11-17 15:04:20 -0700839// layout_geometry
840// : LINESTREAM
841// | POINTSTREAM
842// | TRIANGLESTREAM
843//
844bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
845{
846 // read geometry type
847 const EHlslTokenClass geometryType = peek();
848
849 switch (geometryType) {
850 case EHTokPointStream: geometry = ElgPoints; break;
851 case EHTokLineStream: geometry = ElgLineStrip; break;
852 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
853 default:
854 return false; // not a layout geometry
855 }
856
857 advanceToken(); // consume the layout keyword
858 return true;
859}
860
861// stream_out_template_type
862// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
863//
864bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
865{
866 geometry = ElgNone;
867
868 if (! acceptOutputPrimitiveGeometry(geometry))
869 return false;
870
871 if (! acceptTokenClass(EHTokLeftAngle))
872 return false;
873
874 if (! acceptType(type)) {
875 expected("stream output type");
876 return false;
877 }
878
879 type.getQualifier().storage = EvqVaryingOut;
880
881 if (! acceptTokenClass(EHTokRightAngle)) {
882 expected("right angle bracket");
883 return false;
884 }
885
886 return true;
887}
888
John Kessenicha1e2d492016-09-20 13:22:58 -0600889// annotations
890// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600891//
John Kessenicha1e2d492016-09-20 13:22:58 -0600892bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600893{
John Kessenicha1e2d492016-09-20 13:22:58 -0600894 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600895 return false;
896
John Kessenicha1e2d492016-09-20 13:22:58 -0600897 // note that we are nesting a name space
898 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600899
900 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
901 do {
902 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
903 while (acceptTokenClass(EHTokSemicolon))
904 ;
905
906 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -0600907 break;
John Kessenich86f71382016-09-19 20:23:18 -0600908
909 // declaration
910 TIntermNode* node;
911 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -0600912 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -0600913 return false;
914 }
915 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -0600916
917 parseContext.unnestAnnotations();
918 return true;
John Kessenich86f71382016-09-19 20:23:18 -0600919}
LoopDawg6daaa4f2016-06-23 19:13:48 -0600920
LoopDawg4886f692016-06-29 10:58:58 -0600921// sampler_type
922// : SAMPLER
923// | SAMPLER1D
924// | SAMPLER2D
925// | SAMPLER3D
926// | SAMPLERCUBE
927// | SAMPLERSTATE
928// | SAMPLERCOMPARISONSTATE
929bool HlslGrammar::acceptSamplerType(TType& type)
930{
931 // read sampler type
932 const EHlslTokenClass samplerType = peek();
933
LoopDawga78b0292016-07-19 14:28:05 -0600934 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -0600935 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -0600936
LoopDawga78b0292016-07-19 14:28:05 -0600937 bool isShadow = false;
938
LoopDawg4886f692016-06-29 10:58:58 -0600939 switch (samplerType) {
940 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -0600941 case EHTokSampler1d: /*dim = Esd1D*/; break;
942 case EHTokSampler2d: /*dim = Esd2D*/; break;
943 case EHTokSampler3d: /*dim = Esd3D*/; break;
944 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -0600945 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -0600946 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -0600947 default:
948 return false; // not a sampler declaration
949 }
950
951 advanceToken(); // consume the sampler type keyword
952
953 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -0600954
955 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -0600956 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -0600957
958 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
959
960 return true;
961}
962
963// texture_type
964// | BUFFER
965// | TEXTURE1D
966// | TEXTURE1DARRAY
967// | TEXTURE2D
968// | TEXTURE2DARRAY
969// | TEXTURE3D
970// | TEXTURECUBE
971// | TEXTURECUBEARRAY
972// | TEXTURE2DMS
973// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -0600974// | RWBUFFER
975// | RWTEXTURE1D
976// | RWTEXTURE1DARRAY
977// | RWTEXTURE2D
978// | RWTEXTURE2DARRAY
979// | RWTEXTURE3D
980
LoopDawg4886f692016-06-29 10:58:58 -0600981bool HlslGrammar::acceptTextureType(TType& type)
982{
983 const EHlslTokenClass textureType = peek();
984
985 TSamplerDim dim = EsdNone;
986 bool array = false;
987 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -0600988 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -0600989
990 switch (textureType) {
991 case EHTokBuffer: dim = EsdBuffer; break;
992 case EHTokTexture1d: dim = Esd1D; break;
993 case EHTokTexture1darray: dim = Esd1D; array = true; break;
994 case EHTokTexture2d: dim = Esd2D; break;
995 case EHTokTexture2darray: dim = Esd2D; array = true; break;
996 case EHTokTexture3d: dim = Esd3D; break;
997 case EHTokTextureCube: dim = EsdCube; break;
998 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
999 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1000 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001001 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1002 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1003 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1004 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1005 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1006 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001007 default:
1008 return false; // not a texture declaration
1009 }
1010
1011 advanceToken(); // consume the texture object keyword
1012
1013 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
1014
1015 TIntermTyped* msCount = nullptr;
1016
steve-lunargbb0183f2016-10-04 16:58:14 -06001017 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001018 if (acceptTokenClass(EHTokLeftAngle)) {
1019 if (! acceptType(txType)) {
1020 expected("scalar or vector type");
1021 return false;
1022 }
1023
1024 const TBasicType basicRetType = txType.getBasicType() ;
1025
1026 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1027 unimplemented("basic type in texture");
1028 return false;
1029 }
1030
steve-lunargd53f7172016-07-27 15:46:48 -06001031 // Buffers can handle small mats if they fit in 4 components
1032 if (dim == EsdBuffer && txType.isMatrix()) {
1033 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1034 expected("components < 4 in matrix buffer type");
1035 return false;
1036 }
1037
1038 // TODO: except we don't handle it yet...
1039 unimplemented("matrix type in buffer");
1040 return false;
1041 }
1042
LoopDawg4886f692016-06-29 10:58:58 -06001043 if (!txType.isScalar() && !txType.isVector()) {
1044 expected("scalar or vector type");
1045 return false;
1046 }
1047
LoopDawg4886f692016-06-29 10:58:58 -06001048 if (ms && acceptTokenClass(EHTokComma)) {
1049 // read sample count for multisample types, if given
1050 if (! peekTokenClass(EHTokIntConstant)) {
1051 expected("multisample count");
1052 return false;
1053 }
1054
1055 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1056 return false;
1057 }
1058
1059 if (! acceptTokenClass(EHTokRightAngle)) {
1060 expected("right angle bracket");
1061 return false;
1062 }
1063 } else if (ms) {
1064 expected("texture type for multisample");
1065 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001066 } else if (image) {
1067 expected("type for RWTexture/RWBuffer");
1068 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001069 }
1070
1071 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001072 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001073
1074 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001075 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001076
steve-lunarg4f2da272016-10-10 15:24:57 -06001077 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1078 if (image || dim == EsdBuffer)
1079 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001080
1081 // Non-image Buffers are combined
1082 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001083 sampler.set(txType.getBasicType(), dim, array);
1084 } else {
1085 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001086 if (image) {
1087 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1088 } else {
1089 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1090 }
steve-lunargd53f7172016-07-27 15:46:48 -06001091 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001092
1093 // Remember the declared vector size.
1094 sampler.vectorSize = txType.getVectorSize();
LoopDawg4886f692016-06-29 10:58:58 -06001095
1096 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001097 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001098
1099 return true;
1100}
1101
1102
John Kessenich87142c72016-03-12 20:24:24 -07001103// If token is for a type, update 'type' with the type information,
1104// and return true and advance.
1105// Otherwise, return false, and don't advance
1106bool HlslGrammar::acceptType(TType& type)
1107{
steve-lunarg3226b082016-10-26 19:18:55 -06001108 // Basic types for min* types, broken out here in case of future
1109 // changes, e.g, to use native halfs.
1110 static const TBasicType min16float_bt = EbtFloat;
1111 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001112 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001113 static const TBasicType min16int_bt = EbtInt;
1114 static const TBasicType min12int_bt = EbtInt;
1115 static const TBasicType min16uint_bt = EbtUint;
1116
John Kessenich9c86c6a2016-05-03 22:49:24 -06001117 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001118 case EHTokVector:
1119 return acceptVectorTemplateType(type);
1120 break;
1121
1122 case EHTokMatrix:
1123 return acceptMatrixTemplateType(type);
1124 break;
1125
steve-lunargf49cdf42016-11-17 15:04:20 -07001126 case EHTokPointStream: // fall through
1127 case EHTokLineStream: // ...
1128 case EHTokTriangleStream: // ...
1129 {
1130 TLayoutGeometry geometry;
1131 if (! acceptStreamOutTemplateType(type, geometry))
1132 return false;
1133
1134 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1135 return false;
1136
1137 return true;
1138 }
1139
LoopDawg4886f692016-06-29 10:58:58 -06001140 case EHTokSampler: // fall through
1141 case EHTokSampler1d: // ...
1142 case EHTokSampler2d: // ...
1143 case EHTokSampler3d: // ...
1144 case EHTokSamplerCube: // ...
1145 case EHTokSamplerState: // ...
1146 case EHTokSamplerComparisonState: // ...
1147 return acceptSamplerType(type);
1148 break;
1149
1150 case EHTokBuffer: // fall through
1151 case EHTokTexture1d: // ...
1152 case EHTokTexture1darray: // ...
1153 case EHTokTexture2d: // ...
1154 case EHTokTexture2darray: // ...
1155 case EHTokTexture3d: // ...
1156 case EHTokTextureCube: // ...
1157 case EHTokTextureCubearray: // ...
1158 case EHTokTexture2DMS: // ...
1159 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001160 case EHTokRWTexture1d: // ...
1161 case EHTokRWTexture1darray: // ...
1162 case EHTokRWTexture2d: // ...
1163 case EHTokRWTexture2darray: // ...
1164 case EHTokRWTexture3d: // ...
1165 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001166 return acceptTextureType(type);
1167 break;
1168
John Kesseniche6e74942016-06-11 16:43:14 -06001169 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001170 case EHTokCBuffer:
1171 case EHTokTBuffer:
John Kesseniche6e74942016-06-11 16:43:14 -06001172 return acceptStruct(type);
1173 break;
1174
1175 case EHTokIdentifier:
1176 // An identifier could be for a user-defined type.
1177 // Note we cache the symbol table lookup, to save for a later rule
1178 // when this is not a type.
1179 token.symbol = parseContext.symbolTable.find(*token.string);
1180 if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
1181 type.shallowCopy(token.symbol->getType());
1182 advanceToken();
1183 return true;
1184 } else
1185 return false;
1186
John Kessenich71351de2016-06-08 12:50:56 -06001187 case EHTokVoid:
1188 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001189 break;
John Kessenich71351de2016-06-08 12:50:56 -06001190
John Kessenicha1e2d492016-09-20 13:22:58 -06001191 case EHTokString:
1192 new(&type) TType(EbtString);
1193 break;
1194
John Kessenich87142c72016-03-12 20:24:24 -07001195 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001196 new(&type) TType(EbtFloat);
1197 break;
John Kessenich87142c72016-03-12 20:24:24 -07001198 case EHTokFloat1:
1199 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001200 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001201 break;
John Kessenich87142c72016-03-12 20:24:24 -07001202 case EHTokFloat2:
1203 new(&type) TType(EbtFloat, EvqTemporary, 2);
1204 break;
1205 case EHTokFloat3:
1206 new(&type) TType(EbtFloat, EvqTemporary, 3);
1207 break;
1208 case EHTokFloat4:
1209 new(&type) TType(EbtFloat, EvqTemporary, 4);
1210 break;
1211
John Kessenich71351de2016-06-08 12:50:56 -06001212 case EHTokDouble:
1213 new(&type) TType(EbtDouble);
1214 break;
1215 case EHTokDouble1:
1216 new(&type) TType(EbtDouble);
1217 type.makeVector();
1218 break;
1219 case EHTokDouble2:
1220 new(&type) TType(EbtDouble, EvqTemporary, 2);
1221 break;
1222 case EHTokDouble3:
1223 new(&type) TType(EbtDouble, EvqTemporary, 3);
1224 break;
1225 case EHTokDouble4:
1226 new(&type) TType(EbtDouble, EvqTemporary, 4);
1227 break;
1228
1229 case EHTokInt:
1230 case EHTokDword:
1231 new(&type) TType(EbtInt);
1232 break;
1233 case EHTokInt1:
1234 new(&type) TType(EbtInt);
1235 type.makeVector();
1236 break;
John Kessenich87142c72016-03-12 20:24:24 -07001237 case EHTokInt2:
1238 new(&type) TType(EbtInt, EvqTemporary, 2);
1239 break;
1240 case EHTokInt3:
1241 new(&type) TType(EbtInt, EvqTemporary, 3);
1242 break;
1243 case EHTokInt4:
1244 new(&type) TType(EbtInt, EvqTemporary, 4);
1245 break;
1246
John Kessenich71351de2016-06-08 12:50:56 -06001247 case EHTokUint:
1248 new(&type) TType(EbtUint);
1249 break;
1250 case EHTokUint1:
1251 new(&type) TType(EbtUint);
1252 type.makeVector();
1253 break;
1254 case EHTokUint2:
1255 new(&type) TType(EbtUint, EvqTemporary, 2);
1256 break;
1257 case EHTokUint3:
1258 new(&type) TType(EbtUint, EvqTemporary, 3);
1259 break;
1260 case EHTokUint4:
1261 new(&type) TType(EbtUint, EvqTemporary, 4);
1262 break;
1263
LoopDawg6daaa4f2016-06-23 19:13:48 -06001264
John Kessenich71351de2016-06-08 12:50:56 -06001265 case EHTokBool:
1266 new(&type) TType(EbtBool);
1267 break;
1268 case EHTokBool1:
1269 new(&type) TType(EbtBool);
1270 type.makeVector();
1271 break;
John Kessenich87142c72016-03-12 20:24:24 -07001272 case EHTokBool2:
1273 new(&type) TType(EbtBool, EvqTemporary, 2);
1274 break;
1275 case EHTokBool3:
1276 new(&type) TType(EbtBool, EvqTemporary, 3);
1277 break;
1278 case EHTokBool4:
1279 new(&type) TType(EbtBool, EvqTemporary, 4);
1280 break;
1281
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001282 case EHTokHalf:
1283 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1284 break;
1285 case EHTokHalf1:
1286 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1287 type.makeVector();
1288 break;
1289 case EHTokHalf2:
1290 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1291 break;
1292 case EHTokHalf3:
1293 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1294 break;
1295 case EHTokHalf4:
1296 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1297 break;
1298
steve-lunarg3226b082016-10-26 19:18:55 -06001299 case EHTokMin16float:
1300 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1301 break;
1302 case EHTokMin16float1:
1303 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1304 type.makeVector();
1305 break;
1306 case EHTokMin16float2:
1307 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1308 break;
1309 case EHTokMin16float3:
1310 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1311 break;
1312 case EHTokMin16float4:
1313 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1314 break;
1315
1316 case EHTokMin10float:
1317 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1318 break;
1319 case EHTokMin10float1:
1320 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1321 type.makeVector();
1322 break;
1323 case EHTokMin10float2:
1324 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1325 break;
1326 case EHTokMin10float3:
1327 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1328 break;
1329 case EHTokMin10float4:
1330 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1331 break;
1332
1333 case EHTokMin16int:
1334 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1335 break;
1336 case EHTokMin16int1:
1337 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1338 type.makeVector();
1339 break;
1340 case EHTokMin16int2:
1341 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1342 break;
1343 case EHTokMin16int3:
1344 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1345 break;
1346 case EHTokMin16int4:
1347 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1348 break;
1349
1350 case EHTokMin12int:
1351 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1352 break;
1353 case EHTokMin12int1:
1354 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1355 type.makeVector();
1356 break;
1357 case EHTokMin12int2:
1358 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1359 break;
1360 case EHTokMin12int3:
1361 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1362 break;
1363 case EHTokMin12int4:
1364 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1365 break;
1366
1367 case EHTokMin16uint:
1368 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1369 break;
1370 case EHTokMin16uint1:
1371 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1372 type.makeVector();
1373 break;
1374 case EHTokMin16uint2:
1375 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1376 break;
1377 case EHTokMin16uint3:
1378 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1379 break;
1380 case EHTokMin16uint4:
1381 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1382 break;
1383
John Kessenich0133c122016-05-20 12:17:26 -06001384 case EHTokInt1x1:
1385 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1386 break;
1387 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001388 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001389 break;
1390 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001391 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001392 break;
1393 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001394 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001395 break;
1396 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001397 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001398 break;
1399 case EHTokInt2x2:
1400 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1401 break;
1402 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001403 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001404 break;
1405 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001406 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001407 break;
1408 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001409 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001410 break;
1411 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001412 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001413 break;
1414 case EHTokInt3x3:
1415 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1416 break;
1417 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001418 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001419 break;
1420 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001421 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001422 break;
1423 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001424 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001425 break;
1426 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001427 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001428 break;
1429 case EHTokInt4x4:
1430 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1431 break;
1432
John Kessenich71351de2016-06-08 12:50:56 -06001433 case EHTokUint1x1:
1434 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1435 break;
1436 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001437 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001438 break;
1439 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001440 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001441 break;
1442 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001443 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001444 break;
1445 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001446 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001447 break;
1448 case EHTokUint2x2:
1449 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1450 break;
1451 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001452 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001453 break;
1454 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001455 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001456 break;
1457 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001458 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001459 break;
1460 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001461 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001462 break;
1463 case EHTokUint3x3:
1464 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1465 break;
1466 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001467 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001468 break;
1469 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001470 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001471 break;
1472 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001473 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001474 break;
1475 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001476 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001477 break;
1478 case EHTokUint4x4:
1479 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1480 break;
1481
1482 case EHTokBool1x1:
1483 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1484 break;
1485 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001486 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001487 break;
1488 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001489 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001490 break;
1491 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001492 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001493 break;
1494 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001495 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001496 break;
1497 case EHTokBool2x2:
1498 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1499 break;
1500 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001501 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001502 break;
1503 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001504 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001505 break;
1506 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001507 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001508 break;
1509 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001510 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001511 break;
1512 case EHTokBool3x3:
1513 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1514 break;
1515 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001516 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001517 break;
1518 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001519 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001520 break;
1521 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001522 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001523 break;
1524 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001525 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001526 break;
1527 case EHTokBool4x4:
1528 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1529 break;
1530
John Kessenich0133c122016-05-20 12:17:26 -06001531 case EHTokFloat1x1:
1532 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1533 break;
1534 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001535 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001536 break;
1537 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001538 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001539 break;
1540 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001541 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001542 break;
1543 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001544 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001545 break;
John Kessenich87142c72016-03-12 20:24:24 -07001546 case EHTokFloat2x2:
1547 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1548 break;
1549 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001550 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001551 break;
1552 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001553 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001554 break;
John Kessenich0133c122016-05-20 12:17:26 -06001555 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001556 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001557 break;
John Kessenich87142c72016-03-12 20:24:24 -07001558 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001559 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001560 break;
1561 case EHTokFloat3x3:
1562 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1563 break;
1564 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001565 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001566 break;
John Kessenich0133c122016-05-20 12:17:26 -06001567 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001568 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001569 break;
John Kessenich87142c72016-03-12 20:24:24 -07001570 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001571 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001572 break;
1573 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001574 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001575 break;
1576 case EHTokFloat4x4:
1577 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1578 break;
1579
John Kessenich0133c122016-05-20 12:17:26 -06001580 case EHTokDouble1x1:
1581 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1582 break;
1583 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001584 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001585 break;
1586 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001587 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001588 break;
1589 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001590 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001591 break;
1592 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001593 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001594 break;
1595 case EHTokDouble2x2:
1596 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1597 break;
1598 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001599 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001600 break;
1601 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001603 break;
1604 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001605 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001606 break;
1607 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001608 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001609 break;
1610 case EHTokDouble3x3:
1611 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1612 break;
1613 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001614 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001615 break;
1616 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001618 break;
1619 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001621 break;
1622 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001623 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001624 break;
1625 case EHTokDouble4x4:
1626 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1627 break;
1628
John Kessenich87142c72016-03-12 20:24:24 -07001629 default:
1630 return false;
1631 }
1632
1633 advanceToken();
1634
1635 return true;
1636}
1637
John Kesseniche6e74942016-06-11 16:43:14 -06001638// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001639// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1640// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1641//
1642// struct_type
1643// : STRUCT
1644// | CBUFFER
1645// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001646//
1647bool HlslGrammar::acceptStruct(TType& type)
1648{
John Kessenichb804de62016-09-05 12:19:18 -06001649 // This storage qualifier will tell us whether it's an AST
1650 // block type or just a generic structure type.
1651 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001652
1653 // CBUFFER
1654 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001655 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001656 // TBUFFER
1657 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001658 storageQualifier = EvqBuffer;
John Kesseniche6e74942016-06-11 16:43:14 -06001659 // STRUCT
John Kessenich3d157c52016-07-25 16:05:33 -06001660 else if (! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001661 return false;
1662
1663 // IDENTIFIER
1664 TString structName = "";
1665 if (peekTokenClass(EHTokIdentifier)) {
1666 structName = *token.string;
1667 advanceToken();
1668 }
1669
John Kessenich3d157c52016-07-25 16:05:33 -06001670 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001671 TQualifier postDeclQualifier;
1672 postDeclQualifier.clear();
1673 acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001674
John Kesseniche6e74942016-06-11 16:43:14 -06001675 // LEFT_BRACE
1676 if (! acceptTokenClass(EHTokLeftBrace)) {
1677 expected("{");
1678 return false;
1679 }
1680
1681 // struct_declaration_list
1682 TTypeList* typeList;
1683 if (! acceptStructDeclarationList(typeList)) {
1684 expected("struct member declarations");
1685 return false;
1686 }
1687
1688 // RIGHT_BRACE
1689 if (! acceptTokenClass(EHTokRightBrace)) {
1690 expected("}");
1691 return false;
1692 }
1693
1694 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001695 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001696 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001697 else {
John Kessenich7735b942016-09-05 12:40:06 -06001698 postDeclQualifier.storage = storageQualifier;
1699 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001700 }
John Kesseniche6e74942016-06-11 16:43:14 -06001701
John Kessenich3d157c52016-07-25 16:05:33 -06001702 // If it was named, which means the type can be reused later, add
1703 // it to the symbol table. (Unless it's a block, in which
1704 // case the name is not a type.)
1705 if (type.getBasicType() != EbtBlock && structName.size() > 0) {
John Kesseniche6e74942016-06-11 16:43:14 -06001706 TVariable* userTypeDef = new TVariable(&structName, type, true);
1707 if (! parseContext.symbolTable.insert(*userTypeDef))
1708 parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
1709 }
1710
1711 return true;
1712}
1713
1714// struct_declaration_list
1715// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1716//
1717// struct_declaration
1718// : fully_specified_type struct_declarator COMMA struct_declarator ...
1719//
1720// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001721// : IDENTIFIER post_decls
1722// | IDENTIFIER array_specifier post_decls
John Kesseniche6e74942016-06-11 16:43:14 -06001723//
1724bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
1725{
1726 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001727 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001728
1729 do {
1730 // success on seeing the RIGHT_BRACE coming up
1731 if (peekTokenClass(EHTokRightBrace))
1732 return true;
1733
1734 // struct_declaration
1735
1736 // fully_specified_type
1737 TType memberType;
1738 if (! acceptFullySpecifiedType(memberType)) {
1739 expected("member type");
1740 return false;
1741 }
1742
1743 // struct_declarator COMMA struct_declarator ...
1744 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001745 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001746 expected("member name");
1747 return false;
1748 }
1749
1750 // add it to the list of members
1751 TTypeLoc member = { new TType(EbtVoid), token.loc };
1752 member.type->shallowCopy(memberType);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001753 member.type->setFieldName(*idToken.string);
John Kesseniche6e74942016-06-11 16:43:14 -06001754 typeList->push_back(member);
1755
John Kesseniche6e74942016-06-11 16:43:14 -06001756 // array_specifier
John Kessenich19b92ff2016-06-19 11:50:34 -06001757 TArraySizes* arraySizes = nullptr;
1758 acceptArraySpecifier(arraySizes);
1759 if (arraySizes)
1760 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001761
John Kessenich7735b942016-09-05 12:40:06 -06001762 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06001763
John Kesseniche6e74942016-06-11 16:43:14 -06001764 // success on seeing the SEMICOLON coming up
1765 if (peekTokenClass(EHTokSemicolon))
1766 break;
1767
1768 // COMMA
1769 if (! acceptTokenClass(EHTokComma)) {
1770 expected(",");
1771 return false;
1772 }
1773
1774 } while (true);
1775
1776 // SEMI_COLON
1777 if (! acceptTokenClass(EHTokSemicolon)) {
1778 expected(";");
1779 return false;
1780 }
1781
1782 } while (true);
1783}
1784
John Kessenich5f934b02016-03-13 17:58:25 -06001785// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06001786// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06001787// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001788//
1789bool HlslGrammar::acceptFunctionParameters(TFunction& function)
1790{
John Kessenich078d7f22016-03-14 10:02:11 -06001791 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001792 if (! acceptTokenClass(EHTokLeftParen))
1793 return false;
1794
John Kessenich71351de2016-06-08 12:50:56 -06001795 // VOID RIGHT_PAREN
1796 if (! acceptTokenClass(EHTokVoid)) {
1797 do {
1798 // parameter_declaration
1799 if (! acceptParameterDeclaration(function))
1800 break;
John Kessenich5f934b02016-03-13 17:58:25 -06001801
John Kessenich71351de2016-06-08 12:50:56 -06001802 // COMMA
1803 if (! acceptTokenClass(EHTokComma))
1804 break;
1805 } while (true);
1806 }
John Kessenich5f934b02016-03-13 17:58:25 -06001807
John Kessenich078d7f22016-03-14 10:02:11 -06001808 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001809 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001810 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06001811 return false;
1812 }
1813
1814 return true;
1815}
1816
1817// parameter_declaration
John Kessenichc3387d32016-06-17 14:21:02 -06001818// : fully_specified_type post_decls
John Kessenich19b92ff2016-06-19 11:50:34 -06001819// | fully_specified_type identifier array_specifier post_decls
John Kessenich5f934b02016-03-13 17:58:25 -06001820//
1821bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
1822{
1823 // fully_specified_type
1824 TType* type = new TType;
1825 if (! acceptFullySpecifiedType(*type))
1826 return false;
1827
1828 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06001829 HlslToken idToken;
1830 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06001831
John Kessenich19b92ff2016-06-19 11:50:34 -06001832 // array_specifier
1833 TArraySizes* arraySizes = nullptr;
1834 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06001835 if (arraySizes) {
1836 if (arraySizes->isImplicit()) {
1837 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
1838 return false;
1839 }
1840
John Kessenich19b92ff2016-06-19 11:50:34 -06001841 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06001842 }
John Kessenich19b92ff2016-06-19 11:50:34 -06001843
1844 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001845 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06001846
John Kessenich5aa59e22016-06-17 15:50:47 -06001847 parseContext.paramFix(*type);
1848
John Kessenichaecd4972016-03-14 10:46:34 -06001849 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -06001850 function.addParameter(param);
1851
1852 return true;
1853}
1854
1855// Do the work to create the function definition in addition to
1856// parsing the body (compound_statement).
steve-lunarg1868b142016-10-20 13:07:10 -06001857bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node, const TAttributeMap& attributes)
John Kessenich5f934b02016-03-13 17:58:25 -06001858{
John Kessenicha3051662016-09-02 19:13:36 -06001859 TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
John Kessenich1a4b7752016-09-02 19:05:24 -06001860 TSourceLoc loc = token.loc;
John Kessenich5f934b02016-03-13 17:58:25 -06001861
John Kessenich077e0522016-06-09 02:02:17 -06001862 // This does a pushScope()
steve-lunarg1868b142016-10-20 13:07:10 -06001863 node = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06001864
1865 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06001866 TIntermNode* functionBody = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06001867 if (acceptCompoundStatement(functionBody)) {
John Kessenicha3051662016-09-02 19:13:36 -06001868 parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, node);
John Kessenich5f934b02016-03-13 17:58:25 -06001869 return true;
1870 }
1871
1872 return false;
1873}
1874
John Kessenich0d2b6de2016-06-05 11:23:11 -06001875// Accept an expression with parenthesis around it, where
1876// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06001877// syntactically required ones like in "if ( expression )".
1878//
1879// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06001880//
1881// Note this one is not set up to be speculative; as it gives
1882// errors if not found.
1883//
1884bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
1885{
1886 // LEFT_PAREN
1887 if (! acceptTokenClass(EHTokLeftParen))
1888 expected("(");
1889
John Kessenich5bc4d9a2016-06-20 01:22:38 -06001890 bool decl = false;
1891 TIntermNode* declNode = nullptr;
1892 decl = acceptControlDeclaration(declNode);
1893 if (decl) {
1894 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
1895 expected("initialized declaration");
1896 return false;
1897 } else
1898 expression = declNode->getAsTyped();
1899 } else {
1900 // no declaration
1901 if (! acceptExpression(expression)) {
1902 expected("expression");
1903 return false;
1904 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06001905 }
1906
1907 // RIGHT_PAREN
1908 if (! acceptTokenClass(EHTokRightParen))
1909 expected(")");
1910
1911 return true;
1912}
1913
John Kessenich34fb0362016-05-03 23:17:20 -06001914// The top-level full expression recognizer.
1915//
John Kessenich87142c72016-03-12 20:24:24 -07001916// expression
John Kessenich34fb0362016-05-03 23:17:20 -06001917// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07001918//
1919bool HlslGrammar::acceptExpression(TIntermTyped*& node)
1920{
LoopDawgef764a22016-06-03 09:17:51 -06001921 node = nullptr;
1922
John Kessenich34fb0362016-05-03 23:17:20 -06001923 // assignment_expression
1924 if (! acceptAssignmentExpression(node))
1925 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06001926
John Kessenich34fb0362016-05-03 23:17:20 -06001927 if (! peekTokenClass(EHTokComma))
1928 return true;
1929
1930 do {
1931 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06001932 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06001933 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06001934
John Kessenich34fb0362016-05-03 23:17:20 -06001935 // ... assignment_expression
1936 TIntermTyped* rightNode = nullptr;
1937 if (! acceptAssignmentExpression(rightNode)) {
1938 expected("assignment expression");
1939 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06001940 }
1941
John Kessenich34fb0362016-05-03 23:17:20 -06001942 node = intermediate.addComma(node, rightNode, loc);
1943
1944 if (! peekTokenClass(EHTokComma))
1945 return true;
1946 } while (true);
1947}
1948
John Kessenich07354242016-07-01 19:58:06 -06001949// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07001950// : LEFT_BRACE RIGHT_BRACE
1951// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06001952//
1953// initializer_list
1954// : assignment_expression COMMA assignment_expression COMMA ...
1955//
1956bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
1957{
1958 // LEFT_BRACE
1959 if (! acceptTokenClass(EHTokLeftBrace))
1960 return false;
1961
John Kessenich98ad4852016-11-27 17:39:07 -07001962 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06001963 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07001964 if (acceptTokenClass(EHTokRightBrace)) {
1965 // a zero-length initializer list
1966 node = intermediate.makeAggregate(loc);
1967 return true;
1968 }
1969
1970 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06001971 node = nullptr;
1972 do {
1973 // assignment_expression
1974 TIntermTyped* expr;
1975 if (! acceptAssignmentExpression(expr)) {
1976 expected("assignment expression in initializer list");
1977 return false;
1978 }
1979 node = intermediate.growAggregate(node, expr, loc);
1980
1981 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06001982 if (acceptTokenClass(EHTokComma)) {
1983 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
1984 return true;
John Kessenich07354242016-07-01 19:58:06 -06001985 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06001986 }
John Kessenich07354242016-07-01 19:58:06 -06001987
1988 // RIGHT_BRACE
1989 if (acceptTokenClass(EHTokRightBrace))
1990 return true;
1991
1992 expected(", or }");
1993 return false;
1994 } while (true);
1995}
1996
John Kessenich34fb0362016-05-03 23:17:20 -06001997// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06001998// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06001999//
2000// a op (b op (c op d))
2001//
2002// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002003// : initializer
2004// | conditional_expression
2005// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002006//
2007bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2008{
John Kessenich07354242016-07-01 19:58:06 -06002009 // initializer
2010 if (peekTokenClass(EHTokLeftBrace)) {
2011 if (acceptInitializer(node))
2012 return true;
2013
2014 expected("initializer");
2015 return false;
2016 }
2017
John Kessenich00957f82016-07-27 10:39:57 -06002018 // conditional_expression
2019 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002020 return false;
2021
John Kessenich07354242016-07-01 19:58:06 -06002022 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002023 TOperator assignOp = HlslOpMap::assignment(peek());
2024 if (assignOp == EOpNull)
2025 return true;
2026
John Kessenich00957f82016-07-27 10:39:57 -06002027 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002028 TSourceLoc loc = token.loc;
2029 advanceToken();
2030
John Kessenich00957f82016-07-27 10:39:57 -06002031 // conditional_expression assign_op conditional_expression ...
2032 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002033 // gets the right-to-left associativity.
2034 TIntermTyped* rightNode = nullptr;
2035 if (! acceptAssignmentExpression(rightNode)) {
2036 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002037 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002038 }
2039
John Kessenichd21baed2016-09-16 03:05:12 -06002040 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002041 node = parseContext.handleLvalue(loc, "assign", node);
2042
John Kessenichfea226b2016-07-28 17:53:56 -06002043 if (node == nullptr) {
2044 parseContext.error(loc, "could not create assignment", "", "");
2045 return false;
2046 }
John Kessenich34fb0362016-05-03 23:17:20 -06002047
2048 if (! peekTokenClass(EHTokComma))
2049 return true;
2050
2051 return true;
2052}
2053
John Kessenich00957f82016-07-27 10:39:57 -06002054// Accept a conditional expression, which associates right-to-left,
2055// accomplished by the "true" expression calling down to lower
2056// precedence levels than this level.
2057//
2058// conditional_expression
2059// : binary_expression
2060// | binary_expression QUESTION expression COLON assignment_expression
2061//
2062bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2063{
2064 // binary_expression
2065 if (! acceptBinaryExpression(node, PlLogicalOr))
2066 return false;
2067
2068 if (! acceptTokenClass(EHTokQuestion))
2069 return true;
2070
2071 TIntermTyped* trueNode = nullptr;
2072 if (! acceptExpression(trueNode)) {
2073 expected("expression after ?");
2074 return false;
2075 }
2076 TSourceLoc loc = token.loc;
2077
2078 if (! acceptTokenClass(EHTokColon)) {
2079 expected(":");
2080 return false;
2081 }
2082
2083 TIntermTyped* falseNode = nullptr;
2084 if (! acceptAssignmentExpression(falseNode)) {
2085 expected("expression after :");
2086 return false;
2087 }
2088
2089 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2090
2091 return true;
2092}
2093
John Kessenich34fb0362016-05-03 23:17:20 -06002094// Accept a binary expression, for binary operations that
2095// associate left-to-right. This is, it is implicit, for example
2096//
2097// ((a op b) op c) op d
2098//
2099// binary_expression
2100// : expression op expression op expression ...
2101//
2102// where 'expression' is the next higher level in precedence.
2103//
2104bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2105{
2106 if (precedenceLevel > PlMul)
2107 return acceptUnaryExpression(node);
2108
2109 // assignment_expression
2110 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2111 return false;
2112
John Kessenich34fb0362016-05-03 23:17:20 -06002113 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002114 TOperator op = HlslOpMap::binary(peek());
2115 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2116 if (tokenLevel < precedenceLevel)
2117 return true;
2118
John Kessenich34fb0362016-05-03 23:17:20 -06002119 // ... op
2120 TSourceLoc loc = token.loc;
2121 advanceToken();
2122
2123 // ... expression
2124 TIntermTyped* rightNode = nullptr;
2125 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2126 expected("expression");
2127 return false;
2128 }
2129
2130 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002131 if (node == nullptr) {
2132 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2133 return false;
2134 }
John Kessenich34fb0362016-05-03 23:17:20 -06002135 } while (true);
2136}
2137
2138// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002139// : (type) unary_expression
2140// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002141// | - unary_expression
2142// | ! unary_expression
2143// | ~ unary_expression
2144// | ++ unary_expression
2145// | -- unary_expression
2146// | postfix_expression
2147//
2148bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2149{
John Kessenich1cc1a282016-06-03 16:55:49 -06002150 // (type) unary_expression
2151 // Have to look two steps ahead, because this could be, e.g., a
2152 // postfix_expression instead, since that also starts with at "(".
2153 if (acceptTokenClass(EHTokLeftParen)) {
2154 TType castType;
2155 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002156 if (acceptTokenClass(EHTokRightParen)) {
2157 // We've matched "(type)" now, get the expression to cast
2158 TSourceLoc loc = token.loc;
2159 if (! acceptUnaryExpression(node))
2160 return false;
2161
2162 // Hook it up like a constructor
2163 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2164 if (constructorFunction == nullptr) {
2165 expected("type that can be constructed");
2166 return false;
2167 }
2168 TIntermTyped* arguments = nullptr;
2169 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2170 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2171
2172 return true;
2173 } else {
2174 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2175 // the '(int' part. We must back up twice.
2176 recedeToken();
2177 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002178 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002179 } else {
2180 // This isn't a type cast, but it still started "(", so if it is a
2181 // unary expression, it can only be a postfix_expression, so try that.
2182 // Back it up first.
2183 recedeToken();
2184 return acceptPostfixExpression(node);
2185 }
2186 }
2187
2188 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002189 TOperator unaryOp = HlslOpMap::preUnary(peek());
2190
John Kessenich1cc1a282016-06-03 16:55:49 -06002191 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002192 if (unaryOp == EOpNull)
2193 return acceptPostfixExpression(node);
2194
2195 // op unary_expression
2196 TSourceLoc loc = token.loc;
2197 advanceToken();
2198 if (! acceptUnaryExpression(node))
2199 return false;
2200
2201 // + is a no-op
2202 if (unaryOp == EOpAdd)
2203 return true;
2204
2205 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002206
2207 // These unary ops require lvalues
2208 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2209 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002210
2211 return node != nullptr;
2212}
2213
2214// postfix_expression
2215// : LEFT_PAREN expression RIGHT_PAREN
2216// | literal
2217// | constructor
2218// | identifier
2219// | function_call
2220// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2221// | postfix_expression DOT IDENTIFIER
2222// | postfix_expression INC_OP
2223// | postfix_expression DEC_OP
2224//
2225bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2226{
2227 // Not implemented as self-recursive:
2228 // The logical "right recursion" is done with an loop at the end
2229
2230 // idToken will pick up either a variable or a function name in a function call
2231 HlslToken idToken;
2232
John Kessenich21472ae2016-06-04 11:46:33 -06002233 // Find something before the postfix operations, as they can't operate
2234 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002235 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002236 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002237 if (! acceptExpression(node)) {
2238 expected("expression");
2239 return false;
2240 }
2241 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002242 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002243 return false;
2244 }
John Kessenich34fb0362016-05-03 23:17:20 -06002245 } else if (acceptLiteral(node)) {
2246 // literal (nothing else to do yet), go on to the
2247 } else if (acceptConstructor(node)) {
2248 // constructor (nothing else to do yet)
2249 } else if (acceptIdentifier(idToken)) {
2250 // identifier or function_call name
2251 if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002252 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002253 } else if (acceptFunctionCall(idToken, node)) {
2254 // function_call (nothing else to do yet)
2255 } else {
2256 expected("function call arguments");
2257 return false;
2258 }
John Kessenich21472ae2016-06-04 11:46:33 -06002259 } else {
2260 // nothing found, can't post operate
2261 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002262 }
2263
steve-lunarga2b01a02016-11-28 17:09:54 -07002264 // This is to guarantee we do this no matter how we get out of the stack frame.
2265 // This way there's no bug if an early return forgets to do it.
2266 struct tFinalize {
2267 tFinalize(HlslParseContext& p) : parseContext(p) { }
2268 ~tFinalize() { parseContext.finalizeFlattening(); }
2269 HlslParseContext& parseContext;
2270 } finalize(parseContext);
2271
2272 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2273 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2274 // level: hence the init and finalize. Even though in practice these must be
2275 // constants, they are parsed no matter what.
2276 parseContext.initFlattening();
2277
John Kessenich21472ae2016-06-04 11:46:33 -06002278 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002279 do {
2280 TSourceLoc loc = token.loc;
2281 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002282
John Kessenich34fb0362016-05-03 23:17:20 -06002283 // Consume only a valid post-unary operator, otherwise we are done.
2284 switch (postOp) {
2285 case EOpIndexDirectStruct:
2286 case EOpIndexIndirect:
2287 case EOpPostIncrement:
2288 case EOpPostDecrement:
2289 advanceToken();
2290 break;
2291 default:
2292 return true;
2293 }
John Kessenich87142c72016-03-12 20:24:24 -07002294
John Kessenich34fb0362016-05-03 23:17:20 -06002295 // We have a valid post-unary operator, process it.
2296 switch (postOp) {
2297 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002298 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002299 // DOT IDENTIFIER
2300 // includes swizzles and struct members
John Kessenich93a162a2016-06-17 17:16:27 -06002301 HlslToken field;
2302 if (! acceptIdentifier(field)) {
2303 expected("swizzle or member");
2304 return false;
2305 }
LoopDawg4886f692016-06-29 10:58:58 -06002306
2307 TIntermTyped* base = node; // preserve for method function calls
John Kessenich93a162a2016-06-17 17:16:27 -06002308 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002309
2310 // In the event of a method node, we look for an open paren and accept the function call.
steve-lunarga2b01a02016-11-28 17:09:54 -07002311 if (node != nullptr && node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) {
LoopDawg4886f692016-06-29 10:58:58 -06002312 if (! acceptFunctionCall(field, node, base)) {
2313 expected("function parameters");
2314 return false;
2315 }
2316 }
2317
John Kessenich34fb0362016-05-03 23:17:20 -06002318 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002319 }
John Kessenich34fb0362016-05-03 23:17:20 -06002320 case EOpIndexIndirect:
2321 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002322 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002323 TIntermTyped* indexNode = nullptr;
2324 if (! acceptExpression(indexNode) ||
2325 ! peekTokenClass(EHTokRightBracket)) {
2326 expected("expression followed by ']'");
2327 return false;
2328 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002329 advanceToken();
2330 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2331 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002332 }
2333 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002334 // INC_OP
2335 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002336 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002337 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002338 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002339 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002340 break;
2341 default:
2342 assert(0);
2343 break;
2344 }
2345 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002346}
2347
John Kessenichd016be12016-03-13 11:24:20 -06002348// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002349// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002350//
2351bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2352{
2353 // type
2354 TType type;
2355 if (acceptType(type)) {
2356 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2357 if (constructorFunction == nullptr)
2358 return false;
2359
2360 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002361 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002362 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002363 // It's possible this is a type keyword used as an identifier. Put the token back
2364 // for later use.
2365 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002366 return false;
2367 }
2368
2369 // hook it up
2370 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2371
2372 return true;
2373 }
2374
2375 return false;
2376}
2377
John Kessenich34fb0362016-05-03 23:17:20 -06002378// The function_call identifier was already recognized, and passed in as idToken.
2379//
2380// function_call
2381// : [idToken] arguments
2382//
LoopDawg4886f692016-06-29 10:58:58 -06002383bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base)
John Kessenich34fb0362016-05-03 23:17:20 -06002384{
John Kessenich4678ca92016-05-13 09:33:42 -06002385 // arguments
2386 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
2387 TIntermTyped* arguments = nullptr;
LoopDawg4886f692016-06-29 10:58:58 -06002388
2389 // methods have an implicit first argument of the calling object.
2390 if (base != nullptr)
2391 parseContext.handleFunctionArgument(function, arguments, base);
2392
John Kessenich4678ca92016-05-13 09:33:42 -06002393 if (! acceptArguments(function, arguments))
2394 return false;
2395
2396 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
2397
2398 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002399}
2400
John Kessenich87142c72016-03-12 20:24:24 -07002401// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002402// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002403//
John Kessenichd016be12016-03-13 11:24:20 -06002404// The arguments are pushed onto the 'function' argument list and
2405// onto the 'arguments' aggregate.
2406//
John Kessenich4678ca92016-05-13 09:33:42 -06002407bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002408{
John Kessenich078d7f22016-03-14 10:02:11 -06002409 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002410 if (! acceptTokenClass(EHTokLeftParen))
2411 return false;
2412
2413 do {
John Kessenichd016be12016-03-13 11:24:20 -06002414 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002415 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002416 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002417 break;
John Kessenichd016be12016-03-13 11:24:20 -06002418
2419 // hook it up
2420 parseContext.handleFunctionArgument(function, arguments, arg);
2421
John Kessenich078d7f22016-03-14 10:02:11 -06002422 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002423 if (! acceptTokenClass(EHTokComma))
2424 break;
2425 } while (true);
2426
John Kessenich078d7f22016-03-14 10:02:11 -06002427 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002428 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002429 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002430 return false;
2431 }
2432
2433 return true;
2434}
2435
2436bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2437{
2438 switch (token.tokenClass) {
2439 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002440 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002441 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002442 case EHTokUintConstant:
2443 node = intermediate.addConstantUnion(token.u, token.loc, true);
2444 break;
John Kessenich87142c72016-03-12 20:24:24 -07002445 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002446 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002447 break;
2448 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002449 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002450 break;
2451 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002452 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002453 break;
John Kessenich86f71382016-09-19 20:23:18 -06002454 case EHTokStringConstant:
2455 node = nullptr;
2456 break;
John Kessenich87142c72016-03-12 20:24:24 -07002457
2458 default:
2459 return false;
2460 }
2461
2462 advanceToken();
2463
2464 return true;
2465}
2466
John Kessenich5f934b02016-03-13 17:58:25 -06002467// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002468// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002469//
John Kessenich21472ae2016-06-04 11:46:33 -06002470bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002471{
John Kessenich21472ae2016-06-04 11:46:33 -06002472 TIntermAggregate* compoundStatement = nullptr;
2473
John Kessenich34fb0362016-05-03 23:17:20 -06002474 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002475 if (! acceptTokenClass(EHTokLeftBrace))
2476 return false;
2477
2478 // statement statement ...
2479 TIntermNode* statement = nullptr;
2480 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002481 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2482 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2483 branch->getFlowOp() == EOpDefault)) {
2484 // hook up individual subsequences within a switch statement
2485 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2486 compoundStatement = nullptr;
2487 } else {
2488 // hook it up to the growing compound statement
2489 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2490 }
John Kessenich5f934b02016-03-13 17:58:25 -06002491 }
John Kessenich34fb0362016-05-03 23:17:20 -06002492 if (compoundStatement)
2493 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002494
John Kessenich21472ae2016-06-04 11:46:33 -06002495 retStatement = compoundStatement;
2496
John Kessenich34fb0362016-05-03 23:17:20 -06002497 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002498 return acceptTokenClass(EHTokRightBrace);
2499}
2500
John Kessenich0d2b6de2016-06-05 11:23:11 -06002501bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2502{
2503 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002504 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002505 parseContext.popScope();
2506
2507 return result;
2508}
2509
John Kessenich077e0522016-06-09 02:02:17 -06002510bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002511{
John Kessenich077e0522016-06-09 02:02:17 -06002512 parseContext.pushScope();
2513 bool result = acceptCompoundStatement(statement);
2514 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002515
2516 return result;
2517}
2518
John Kessenich5f934b02016-03-13 17:58:25 -06002519// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002520// : attributes attributed_statement
2521//
2522// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002523// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002524// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002525// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002526// | declaration_statement
2527// | selection_statement
2528// | switch_statement
2529// | case_label
2530// | iteration_statement
2531// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002532//
2533bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2534{
John Kessenich21472ae2016-06-04 11:46:33 -06002535 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002536
John Kessenich21472ae2016-06-04 11:46:33 -06002537 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002538 TAttributeMap attributes;
2539 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002540
John Kessenich21472ae2016-06-04 11:46:33 -06002541 // attributed_statement
2542 switch (peek()) {
2543 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002544 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002545
John Kessenich21472ae2016-06-04 11:46:33 -06002546 case EHTokIf:
2547 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002548
John Kessenich21472ae2016-06-04 11:46:33 -06002549 case EHTokSwitch:
2550 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002551
John Kessenich21472ae2016-06-04 11:46:33 -06002552 case EHTokFor:
2553 case EHTokDo:
2554 case EHTokWhile:
2555 return acceptIterationStatement(statement);
2556
2557 case EHTokContinue:
2558 case EHTokBreak:
2559 case EHTokDiscard:
2560 case EHTokReturn:
2561 return acceptJumpStatement(statement);
2562
2563 case EHTokCase:
2564 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002565 case EHTokDefault:
2566 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002567
2568 case EHTokSemicolon:
2569 return acceptTokenClass(EHTokSemicolon);
2570
2571 case EHTokRightBrace:
2572 // Performance: not strictly necessary, but stops a bunch of hunting early,
2573 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002574 return false;
2575
John Kessenich21472ae2016-06-04 11:46:33 -06002576 default:
2577 {
2578 // declaration
2579 if (acceptDeclaration(statement))
2580 return true;
2581
2582 // expression
2583 TIntermTyped* node;
2584 if (acceptExpression(node))
2585 statement = node;
2586 else
2587 return false;
2588
2589 // SEMICOLON (following an expression)
2590 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002591 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002592 return false;
2593 }
2594 }
2595 }
2596
John Kessenich5f934b02016-03-13 17:58:25 -06002597 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002598}
2599
John Kessenich21472ae2016-06-04 11:46:33 -06002600// attributes
2601// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2602//
2603// attribute:
2604// : UNROLL
2605// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2606// | FASTOPT
2607// | ALLOW_UAV_CONDITION
2608// | BRANCH
2609// | FLATTEN
2610// | FORCECASE
2611// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06002612// | DOMAIN
2613// | EARLYDEPTHSTENCIL
2614// | INSTANCE
2615// | MAXTESSFACTOR
2616// | OUTPUTCONTROLPOINTS
2617// | OUTPUTTOPOLOGY
2618// | PARTITIONING
2619// | PATCHCONSTANTFUNC
2620// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06002621//
steve-lunarg1868b142016-10-20 13:07:10 -06002622void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06002623{
steve-lunarg1868b142016-10-20 13:07:10 -06002624 // For now, accept the [ XXX(X) ] syntax, but drop all but
2625 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06002626 // TODO: subset to correct set? Pass on?
2627 do {
steve-lunarg1868b142016-10-20 13:07:10 -06002628 HlslToken idToken;
2629
John Kessenich0d2b6de2016-06-05 11:23:11 -06002630 // LEFT_BRACKET?
2631 if (! acceptTokenClass(EHTokLeftBracket))
2632 return;
2633
2634 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06002635 if (acceptIdentifier(idToken)) {
2636 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06002637 } else if (! peekTokenClass(EHTokRightBracket)) {
2638 expected("identifier");
2639 advanceToken();
2640 }
2641
steve-lunarga22f7db2016-11-11 08:17:44 -07002642 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06002643
2644 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002645 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07002646 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06002647
John Kessenich0d2b6de2016-06-05 11:23:11 -06002648 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07002649 bool expectingExpression = false;
steve-lunarg1868b142016-10-20 13:07:10 -06002650
steve-lunarga22f7db2016-11-11 08:17:44 -07002651 while (acceptAssignmentExpression(node)) {
2652 expectingExpression = false;
2653 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06002654 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07002655 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06002656 }
2657
steve-lunarga22f7db2016-11-11 08:17:44 -07002658 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06002659 if (! acceptTokenClass(EHTokRightParen))
2660 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07002661
2662 // Error for partial or missing expression
2663 if (expectingExpression || expressions->getSequence().empty())
2664 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06002665 }
2666
2667 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06002668 if (!acceptTokenClass(EHTokRightBracket)) {
2669 expected("]");
2670 return;
2671 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002672
steve-lunarg1868b142016-10-20 13:07:10 -06002673 // Add any values we found into the attribute map. This accepts
2674 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07002675 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002676 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06002677}
2678
John Kessenich0d2b6de2016-06-05 11:23:11 -06002679// selection_statement
2680// : IF LEFT_PAREN expression RIGHT_PAREN statement
2681// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
2682//
John Kessenich21472ae2016-06-04 11:46:33 -06002683bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
2684{
John Kessenich0d2b6de2016-06-05 11:23:11 -06002685 TSourceLoc loc = token.loc;
2686
2687 // IF
2688 if (! acceptTokenClass(EHTokIf))
2689 return false;
2690
2691 // so that something declared in the condition is scoped to the lifetimes
2692 // of the then-else statements
2693 parseContext.pushScope();
2694
2695 // LEFT_PAREN expression RIGHT_PAREN
2696 TIntermTyped* condition;
2697 if (! acceptParenExpression(condition))
2698 return false;
2699
2700 // create the child statements
2701 TIntermNodePair thenElse = { nullptr, nullptr };
2702
2703 // then statement
2704 if (! acceptScopedStatement(thenElse.node1)) {
2705 expected("then statement");
2706 return false;
2707 }
2708
2709 // ELSE
2710 if (acceptTokenClass(EHTokElse)) {
2711 // else statement
2712 if (! acceptScopedStatement(thenElse.node2)) {
2713 expected("else statement");
2714 return false;
2715 }
2716 }
2717
2718 // Put the pieces together
2719 statement = intermediate.addSelection(condition, thenElse, loc);
2720 parseContext.popScope();
2721
2722 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002723}
2724
John Kessenichd02dc5d2016-07-01 00:04:11 -06002725// switch_statement
2726// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
2727//
John Kessenich21472ae2016-06-04 11:46:33 -06002728bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
2729{
John Kessenichd02dc5d2016-07-01 00:04:11 -06002730 // SWITCH
2731 TSourceLoc loc = token.loc;
2732 if (! acceptTokenClass(EHTokSwitch))
2733 return false;
2734
2735 // LEFT_PAREN expression RIGHT_PAREN
2736 parseContext.pushScope();
2737 TIntermTyped* switchExpression;
2738 if (! acceptParenExpression(switchExpression)) {
2739 parseContext.popScope();
2740 return false;
2741 }
2742
2743 // compound_statement
2744 parseContext.pushSwitchSequence(new TIntermSequence);
2745 bool statementOkay = acceptCompoundStatement(statement);
2746 if (statementOkay)
2747 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
2748
2749 parseContext.popSwitchSequence();
2750 parseContext.popScope();
2751
2752 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06002753}
2754
John Kessenich119f8f62016-06-05 15:44:07 -06002755// iteration_statement
2756// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
2757// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
2758// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
2759//
2760// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06002761bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
2762{
John Kessenich119f8f62016-06-05 15:44:07 -06002763 TSourceLoc loc = token.loc;
2764 TIntermTyped* condition = nullptr;
2765
2766 EHlslTokenClass loop = peek();
2767 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
2768
2769 // WHILE or DO or FOR
2770 advanceToken();
2771
2772 switch (loop) {
2773 case EHTokWhile:
2774 // so that something declared in the condition is scoped to the lifetime
2775 // of the while sub-statement
2776 parseContext.pushScope();
2777 parseContext.nestLooping();
2778
2779 // LEFT_PAREN condition RIGHT_PAREN
2780 if (! acceptParenExpression(condition))
2781 return false;
2782
2783 // statement
2784 if (! acceptScopedStatement(statement)) {
2785 expected("while sub-statement");
2786 return false;
2787 }
2788
2789 parseContext.unnestLooping();
2790 parseContext.popScope();
2791
2792 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
2793
2794 return true;
2795
2796 case EHTokDo:
2797 parseContext.nestLooping();
2798
2799 if (! acceptTokenClass(EHTokLeftBrace))
2800 expected("{");
2801
2802 // statement
2803 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
2804 expected("do sub-statement");
2805 return false;
2806 }
2807
2808 if (! acceptTokenClass(EHTokRightBrace))
2809 expected("}");
2810
2811 // WHILE
2812 if (! acceptTokenClass(EHTokWhile)) {
2813 expected("while");
2814 return false;
2815 }
2816
2817 // LEFT_PAREN condition RIGHT_PAREN
2818 TIntermTyped* condition;
2819 if (! acceptParenExpression(condition))
2820 return false;
2821
2822 if (! acceptTokenClass(EHTokSemicolon))
2823 expected(";");
2824
2825 parseContext.unnestLooping();
2826
2827 statement = intermediate.addLoop(statement, condition, 0, false, loc);
2828
2829 return true;
2830
2831 case EHTokFor:
2832 {
2833 // LEFT_PAREN
2834 if (! acceptTokenClass(EHTokLeftParen))
2835 expected("(");
2836
2837 // so that something declared in the condition is scoped to the lifetime
2838 // of the for sub-statement
2839 parseContext.pushScope();
2840
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002841 // initializer
2842 TIntermNode* initNode = nullptr;
2843 if (! acceptControlDeclaration(initNode)) {
2844 TIntermTyped* initExpr = nullptr;
2845 acceptExpression(initExpr);
2846 initNode = initExpr;
2847 }
2848 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06002849 if (! acceptTokenClass(EHTokSemicolon))
2850 expected(";");
2851
2852 parseContext.nestLooping();
2853
2854 // condition SEMI_COLON
2855 acceptExpression(condition);
2856 if (! acceptTokenClass(EHTokSemicolon))
2857 expected(";");
2858
2859 // iterator SEMI_COLON
2860 TIntermTyped* iterator = nullptr;
2861 acceptExpression(iterator);
2862 if (! acceptTokenClass(EHTokRightParen))
2863 expected(")");
2864
2865 // statement
2866 if (! acceptScopedStatement(statement)) {
2867 expected("for sub-statement");
2868 return false;
2869 }
2870
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002871 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06002872
2873 parseContext.popScope();
2874 parseContext.unnestLooping();
2875
2876 return true;
2877 }
2878
2879 default:
2880 return false;
2881 }
John Kessenich21472ae2016-06-04 11:46:33 -06002882}
2883
2884// jump_statement
2885// : CONTINUE SEMICOLON
2886// | BREAK SEMICOLON
2887// | DISCARD SEMICOLON
2888// | RETURN SEMICOLON
2889// | RETURN expression SEMICOLON
2890//
2891bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
2892{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002893 EHlslTokenClass jump = peek();
2894 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06002895 case EHTokContinue:
2896 case EHTokBreak:
2897 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06002898 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002899 advanceToken();
2900 break;
John Kessenich21472ae2016-06-04 11:46:33 -06002901 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002902 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06002903 return false;
2904 }
John Kessenich21472ae2016-06-04 11:46:33 -06002905
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002906 switch (jump) {
2907 case EHTokContinue:
2908 statement = intermediate.addBranch(EOpContinue, token.loc);
2909 break;
2910 case EHTokBreak:
2911 statement = intermediate.addBranch(EOpBreak, token.loc);
2912 break;
2913 case EHTokDiscard:
2914 statement = intermediate.addBranch(EOpKill, token.loc);
2915 break;
2916
2917 case EHTokReturn:
2918 {
2919 // expression
2920 TIntermTyped* node;
2921 if (acceptExpression(node)) {
2922 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06002923 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002924 } else
2925 statement = intermediate.addBranch(EOpReturn, token.loc);
2926 break;
2927 }
2928
2929 default:
2930 assert(0);
2931 return false;
2932 }
2933
2934 // SEMICOLON
2935 if (! acceptTokenClass(EHTokSemicolon))
2936 expected(";");
2937
2938 return true;
2939}
John Kessenich21472ae2016-06-04 11:46:33 -06002940
John Kessenichd02dc5d2016-07-01 00:04:11 -06002941// case_label
2942// : CASE expression COLON
2943//
John Kessenich21472ae2016-06-04 11:46:33 -06002944bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
2945{
John Kessenichd02dc5d2016-07-01 00:04:11 -06002946 TSourceLoc loc = token.loc;
2947 if (! acceptTokenClass(EHTokCase))
2948 return false;
2949
2950 TIntermTyped* expression;
2951 if (! acceptExpression(expression)) {
2952 expected("case expression");
2953 return false;
2954 }
2955
2956 if (! acceptTokenClass(EHTokColon)) {
2957 expected(":");
2958 return false;
2959 }
2960
2961 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
2962
2963 return true;
2964}
2965
2966// default_label
2967// : DEFAULT COLON
2968//
2969bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
2970{
2971 TSourceLoc loc = token.loc;
2972 if (! acceptTokenClass(EHTokDefault))
2973 return false;
2974
2975 if (! acceptTokenClass(EHTokColon)) {
2976 expected(":");
2977 return false;
2978 }
2979
2980 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
2981
2982 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002983}
2984
John Kessenich19b92ff2016-06-19 11:50:34 -06002985// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06002986// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
2987// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06002988//
2989void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
2990{
2991 arraySizes = nullptr;
2992
steve-lunarg7b211a32016-10-13 12:26:18 -06002993 // Early-out if there aren't any array dimensions
2994 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06002995 return;
2996
steve-lunarg7b211a32016-10-13 12:26:18 -06002997 // If we get here, we have at least one array dimension. This will track the sizes we find.
John Kessenich19b92ff2016-06-19 11:50:34 -06002998 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06002999
3000 // Collect each array dimension.
3001 while (acceptTokenClass(EHTokLeftBracket)) {
3002 TSourceLoc loc = token.loc;
3003 TIntermTyped* sizeExpr = nullptr;
3004
3005 // Array sizing expression is optional. If ommitted, array will be later sized by initializer list.
3006 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3007
3008 if (! acceptTokenClass(EHTokRightBracket)) {
3009 expected("]");
3010 return;
3011 }
3012
3013 if (hasArraySize) {
3014 TArraySize arraySize;
3015 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3016 arraySizes->addInnerSize(arraySize);
3017 } else {
3018 arraySizes->addInnerSize(0); // sized by initializers.
3019 }
steve-lunarg265c0612016-09-27 10:57:35 -06003020 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003021}
3022
John Kessenich630dd7d2016-06-12 23:52:12 -06003023// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003024// : COLON semantic // optional
3025// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3026// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003027// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003028// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003029//
John Kessenich7735b942016-09-05 12:40:06 -06003030void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003031{
John Kessenich630dd7d2016-06-12 23:52:12 -06003032 do {
3033 // COLON
3034 if (acceptTokenClass(EHTokColon)) {
3035 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003036 if (peekTokenClass(EHTokLayout))
3037 acceptLayoutQualifierList(qualifier);
3038 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003039 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003040 if (! acceptTokenClass(EHTokLeftParen)) {
3041 expected("(");
3042 return;
3043 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003044 HlslToken locationToken;
3045 if (! acceptIdentifier(locationToken)) {
3046 expected("c[subcomponent][.component]");
3047 return;
3048 }
3049 HlslToken componentToken;
3050 if (acceptTokenClass(EHTokDot)) {
3051 if (! acceptIdentifier(componentToken)) {
3052 expected("component");
3053 return;
3054 }
3055 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003056 if (! acceptTokenClass(EHTokRightParen)) {
3057 expected(")");
3058 break;
3059 }
John Kessenich7735b942016-09-05 12:40:06 -06003060 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003061 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003062 expected("layout, semantic, packoffset, or register");
John Kessenich630dd7d2016-06-12 23:52:12 -06003063 return;
3064 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003065 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3066 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003067 if (! acceptTokenClass(EHTokLeftParen)) {
3068 expected("(");
3069 return;
3070 }
John Kessenichb38f0712016-07-30 10:29:54 -06003071 HlslToken registerDesc; // for Type#
3072 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003073 if (! acceptIdentifier(registerDesc)) {
3074 expected("register number description");
3075 return;
3076 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003077 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3078 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003079 // Then we didn't really see the registerDesc yet, it was
3080 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003081 profile = registerDesc;
3082 if (! acceptIdentifier(registerDesc)) {
3083 expected("register number description");
3084 return;
3085 }
3086 }
John Kessenichb38f0712016-07-30 10:29:54 -06003087 int subComponent = 0;
3088 if (acceptTokenClass(EHTokLeftBracket)) {
3089 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3090 if (! peekTokenClass(EHTokIntConstant)) {
3091 expected("literal integer");
3092 return;
3093 }
3094 subComponent = token.i;
3095 advanceToken();
3096 if (! acceptTokenClass(EHTokRightBracket)) {
3097 expected("]");
3098 break;
3099 }
3100 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003101 // (COMMA SPACEN)opt
3102 HlslToken spaceDesc;
3103 if (acceptTokenClass(EHTokComma)) {
3104 if (! acceptIdentifier(spaceDesc)) {
3105 expected ("space identifier");
3106 return;
3107 }
3108 }
3109 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003110 if (! acceptTokenClass(EHTokRightParen)) {
3111 expected(")");
3112 break;
3113 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003114 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003115 } else {
3116 // semantic, in idToken.string
John Kessenich7735b942016-09-05 12:40:06 -06003117 parseContext.handleSemantic(idToken.loc, qualifier, *idToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003118 }
John Kessenicha1e2d492016-09-20 13:22:58 -06003119 } else if (peekTokenClass(EHTokLeftAngle))
3120 acceptAnnotations(qualifier);
3121 else
John Kessenich630dd7d2016-06-12 23:52:12 -06003122 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003123
John Kessenich630dd7d2016-06-12 23:52:12 -06003124 } while (true);
John Kessenich078d7f22016-03-14 10:02:11 -06003125}
3126
John Kesseniche01a9bc2016-03-12 20:11:22 -07003127} // end namespace glslang