blob: a5fc9e6d78d6f3dfe03736a0057237d4ea14bc75 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2016 Google, Inc.
3// Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kesseniche01a9bc2016-03-12 20:11:22 -07006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kesseniche01a9bc2016-03-12 20:11:22 -070010//
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//
John Kessenich927608b2017-01-06 12:34:14 -070023// 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.
John Kesseniche01a9bc2016-03-12 20:11:22 -070035//
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.
John Kessenichecba76f2017-01-06 00:34:48 -070092
steve-lunarg5ca85ad2016-12-26 18:45:52 -070093 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
John Kessenichca71d942017-03-07 20:44:09 -0700134 if (! acceptDeclaration(unitNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -0700135 return false;
136 }
137
John Kessenichd016be12016-03-13 11:24:20 -0600138 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700139 if (unitNode && !unitNode->getAsAggregate())
140 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600141 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600142
John Kesseniche01a9bc2016-03-12 20:11:22 -0700143 return true;
144}
145
LoopDawg4886f692016-06-29 10:58:58 -0600146// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700147// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600148//
149// sampler_state_assignment
150// : sampler_state_identifier EQUAL value SEMICOLON
151//
152// sampler_state_identifier
153// : ADDRESSU
154// | ADDRESSV
155// | ADDRESSW
156// | BORDERCOLOR
157// | FILTER
158// | MAXANISOTROPY
159// | MAXLOD
160// | MINLOD
161// | MIPLODBIAS
162//
163bool HlslGrammar::acceptSamplerState()
164{
165 // TODO: this should be genericized to accept a list of valid tokens and
166 // return token/value pairs. Presently it is specific to texture values.
167
168 if (! acceptTokenClass(EHTokLeftBrace))
169 return true;
170
171 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700172
LoopDawg4886f692016-06-29 10:58:58 -0600173 do {
174 // read state name
175 HlslToken state;
176 if (! acceptIdentifier(state))
177 break; // end of list
178
179 // FXC accepts any case
180 TString stateName = *state.string;
181 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
182
183 if (! acceptTokenClass(EHTokAssign)) {
184 expected("assign");
185 return false;
186 }
187
188 if (stateName == "minlod" || stateName == "maxlod") {
189 if (! peekTokenClass(EHTokIntConstant)) {
190 expected("integer");
191 return false;
192 }
193
194 TIntermTyped* lod = nullptr;
195 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
196 return false;
197 } else if (stateName == "maxanisotropy") {
198 if (! peekTokenClass(EHTokIntConstant)) {
199 expected("integer");
200 return false;
201 }
202
203 TIntermTyped* maxAnisotropy = nullptr;
204 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
205 return false;
206 } else if (stateName == "filter") {
207 HlslToken filterMode;
208 if (! acceptIdentifier(filterMode)) {
209 expected("filter mode");
210 return false;
211 }
212 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
213 HlslToken addrMode;
214 if (! acceptIdentifier(addrMode)) {
215 expected("texture address mode");
216 return false;
217 }
218 } else if (stateName == "miplodbias") {
219 TIntermTyped* lodBias = nullptr;
220 if (! acceptLiteral(lodBias)) {
221 expected("lod bias");
222 return false;
223 }
224 } else if (stateName == "bordercolor") {
225 return false;
226 } else {
227 expected("texture state");
228 return false;
229 }
230
231 // SEMICOLON
232 if (! acceptTokenClass(EHTokSemicolon)) {
233 expected("semicolon");
234 return false;
235 }
236 } while (true);
237
238 if (! acceptTokenClass(EHTokRightBrace))
239 return false;
240
241 return true;
242}
243
244// sampler_declaration_dx9
245// : SAMPLER identifier EQUAL sampler_type sampler_state
246//
John Kesseniche4821e42016-07-16 10:19:43 -0600247bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600248{
249 if (! acceptTokenClass(EHTokSampler))
250 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700251
LoopDawg4886f692016-06-29 10:58:58 -0600252 // TODO: remove this when DX9 style declarations are implemented.
253 unimplemented("Direct3D 9 sampler declaration");
254
255 // read sampler name
256 HlslToken name;
257 if (! acceptIdentifier(name)) {
258 expected("sampler name");
259 return false;
260 }
261
262 if (! acceptTokenClass(EHTokAssign)) {
263 expected("=");
264 return false;
265 }
266
267 return false;
268}
269
John Kesseniche01a9bc2016-03-12 20:11:22 -0700270// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600271// : sampler_declaration_dx9 post_decls SEMICOLON
272// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600273// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600274// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600275// | typedef declaration
John Kessenich87142c72016-03-12 20:24:24 -0700276//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600277// declarator_list
278// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600279//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600280// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600281// : identifier array_specifier post_decls
282// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600283// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600284//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600285// Parsing has to go pretty far in to know whether it's a variable, prototype, or
286// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600287// as above. (The 'identifier' in the first item in init_declarator list is the
288// same as 'identifier' for function declarations.)
289//
John Kessenichca71d942017-03-07 20:44:09 -0700290// This can generate more than one subtree, one per initializer or a function body.
291// All initializer subtrees are put in their own aggregate node, making one top-level
292// node for all the initializers. Each function created is a top-level node to grow
293// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600294//
John Kessenichca71d942017-03-07 20:44:09 -0700295// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
296// each top-level node the declaration creates. Otherwise, if only one top-level
297// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700298//
John Kessenichca71d942017-03-07 20:44:09 -0700299bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700300{
John Kessenich54ee28f2017-03-11 14:13:00 -0700301 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600302
steve-lunarg1868b142016-10-20 13:07:10 -0600303 // attributes
304 TAttributeMap attributes;
305 acceptAttributes(attributes);
306
John Kessenich5e69ec62016-07-05 00:02:40 -0600307 // typedef
308 bool typedefDecl = acceptTokenClass(EHTokTypedef);
309
John Kesseniche82061d2016-09-27 14:38:57 -0600310 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600311
312 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600313 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
314 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
315 // HLSL shaders, this will have to be a master level switch
316 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700317 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700318 // if (acceptSamplerDeclarationDX9(declaredType))
319 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600320
321 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700322 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700323 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600324
John Kessenich87142c72016-03-12 20:24:24 -0700325 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600326 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700327 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600328 while (acceptIdentifier(idToken)) {
John Kessenich78388722017-03-08 18:53:51 -0700329 if (peekTokenClass(EHTokLeftParen)) {
330 // looks like function parameters
331 TString* fnName = idToken.string;
steve-lunargf1e0c872016-10-31 15:13:43 -0600332
John Kessenich78388722017-03-08 18:53:51 -0700333 // Potentially rename shader entry point function. No-op most of the time.
334 parseContext.renameShaderFunction(fnName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600335
John Kessenich78388722017-03-08 18:53:51 -0700336 // function_parameters
337 TFunction& function = *new TFunction(fnName, declaredType);
338 if (!acceptFunctionParameters(function)) {
339 expected("function parameter list");
340 return false;
341 }
342
John Kessenich630dd7d2016-06-12 23:52:12 -0600343 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -0600344 acceptPostDecls(function.getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600345
John Kessenichd5ed0b62016-07-04 17:32:45 -0600346 // compound_statement (function body definition) or just a prototype?
347 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700348 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600349 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600350 if (typedefDecl)
351 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichca71d942017-03-07 20:44:09 -0700352 return acceptFunctionDefinition(function, nodeList, attributes);
John Kessenich5e69ec62016-07-05 00:02:40 -0600353 } else {
354 if (typedefDecl)
355 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich9e079532016-09-02 20:05:19 -0600356 parseContext.handleFunctionDeclarator(idToken.loc, function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600357 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600358 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600359 // A variable declaration. Fix the storage qualifier if it's a global.
360 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
361 declaredType.getQualifier().storage = EvqUniform;
362
John Kessenichecba76f2017-01-06 00:34:48 -0700363 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600364 // the number of types can expand when arrayness is different.
365 TType variableType;
366 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600367
John Kesseniche82061d2016-09-27 14:38:57 -0600368 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600369 TArraySizes* arraySizes = nullptr;
370 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600371
John Kesseniche82061d2016-09-27 14:38:57 -0600372 // Fix arrayness in the variableType
373 if (declaredType.isImplicitlySizedArray()) {
374 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
375 // of different sizes, for this case sharing the shallow copy of arrayness
376 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
377 variableType.newArraySizes(declaredType.getArraySizes());
378 }
379 if (arraySizes || variableType.isArray()) {
380 // In the most general case, arrayness is potentially coming both from the
381 // declared type and from the variable: "int[] a[];" or just one or the other.
382 // Merge it all to the variableType, so all arrayness is part of the variableType.
383 parseContext.arrayDimMerge(variableType, arraySizes);
384 }
385
LoopDawg4886f692016-06-29 10:58:58 -0600386 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600387 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600388 if (! acceptSamplerState())
389 return false;
390 }
391
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600393 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600394
395 // EQUAL assignment_expression
396 TIntermTyped* expressionNode = nullptr;
397 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600398 if (typedefDecl)
399 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600400 if (! acceptAssignmentExpression(expressionNode)) {
401 expected("initializer");
402 return false;
403 }
404 }
405
John Kessenich6dbc0a72016-09-27 19:13:05 -0600406 // TODO: things scoped within an annotation need their own name space;
407 // TODO: strings are not yet handled.
408 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
409 if (typedefDecl)
410 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
411 else if (variableType.getBasicType() == EbtBlock)
steve-lunargdd8287a2017-02-23 18:04:12 -0700412 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600413 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700414 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600415 // this isn't really an individual variable, but a member of the $Global buffer
416 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
417 } else {
418 // Declare the variable and add any initializer code to the AST.
419 // The top-level node is always made into an aggregate, as that's
420 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700421 initializers = intermediate.growAggregate(initializers,
422 parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
423 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600424 }
425 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600426 }
John Kessenich5f934b02016-03-13 17:58:25 -0600427 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600428
429 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700430 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600431 continue;
432 }
433 };
434
John Kessenichca71d942017-03-07 20:44:09 -0700435 // The top-level initializer node is a sequence.
436 if (initializers != nullptr)
437 initializers->setOperator(EOpSequence);
438
439 // Add the initializers' aggregate to the nodeList we were handed.
440 if (nodeList)
441 nodeList = intermediate.growAggregate(nodeList, initializers);
442 else
443 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700444
John Kessenich078d7f22016-03-14 10:02:11 -0600445 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600446 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700447 // This may have been a false detection of what appeared to be a declaration, but
448 // was actually an assignment such as "float = 4", where "float" is an identifier.
449 // We put the token back to let further parsing happen for cases where that may
450 // happen. This errors on the side of caution, and mostly triggers the error.
451
452 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
453 recedeToken();
454 else
455 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600456 return false;
457 }
John Kessenichecba76f2017-01-06 00:34:48 -0700458
John Kesseniche01a9bc2016-03-12 20:11:22 -0700459 return true;
460}
461
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600462// control_declaration
463// : fully_specified_type identifier EQUAL expression
464//
465bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
466{
467 node = nullptr;
468
469 // fully_specified_type
470 TType type;
471 if (! acceptFullySpecifiedType(type))
472 return false;
473
John Kessenich057df292017-03-06 18:18:37 -0700474 // filter out type casts
475 if (peekTokenClass(EHTokLeftParen)) {
476 recedeToken();
477 return false;
478 }
479
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600480 // identifier
481 HlslToken idToken;
482 if (! acceptIdentifier(idToken)) {
483 expected("identifier");
484 return false;
485 }
486
487 // EQUAL
488 TIntermTyped* expressionNode = nullptr;
489 if (! acceptTokenClass(EHTokAssign)) {
490 expected("=");
491 return false;
492 }
493
494 // expression
495 if (! acceptExpression(expressionNode)) {
496 expected("initializer");
497 return false;
498 }
499
John Kesseniche82061d2016-09-27 14:38:57 -0600500 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600501
502 return true;
503}
504
John Kessenich87142c72016-03-12 20:24:24 -0700505// fully_specified_type
506// : type_specifier
507// | type_qualifier type_specifier
508//
509bool HlslGrammar::acceptFullySpecifiedType(TType& type)
510{
John Kessenich54ee28f2017-03-11 14:13:00 -0700511 TIntermNode* nodeList = nullptr;
512 return acceptFullySpecifiedType(type, nodeList);
513}
514bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
515{
John Kessenich87142c72016-03-12 20:24:24 -0700516 // type_qualifier
517 TQualifier qualifier;
518 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600519 if (! acceptQualifier(qualifier))
520 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600521 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700522
523 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700524 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700525 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700526 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700527 // qualifier. Back it out, if we did.
528 if (qualifier.sample)
529 recedeToken();
530
John Kessenich87142c72016-03-12 20:24:24 -0700531 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700532 }
John Kessenich3d157c52016-07-25 16:05:33 -0600533 if (type.getBasicType() == EbtBlock) {
534 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600535 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600536 // further, it can create an anonymous instance of the block
537 if (peekTokenClass(EHTokSemicolon))
538 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600539 } else {
540 // Some qualifiers are set when parsing the type. Merge those with
541 // whatever comes from acceptQualifier.
542 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700543
steve-lunargbb0183f2016-10-04 16:58:14 -0600544 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600545 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700546
steve-lunarg5da1f032017-02-12 17:50:28 -0700547 if (type.getQualifier().storage == EvqVaryingOut ||
548 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700549 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700550 qualifier.readonly = type.getQualifier().readonly;
551 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700552
553 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600554 }
John Kessenich87142c72016-03-12 20:24:24 -0700555
556 return true;
557}
558
John Kessenich630dd7d2016-06-12 23:52:12 -0600559// type_qualifier
560// : qualifier qualifier ...
561//
562// Zero or more of these, so this can't return false.
563//
John Kessenichb9e39122016-08-17 10:22:08 -0600564bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700565{
John Kessenich630dd7d2016-06-12 23:52:12 -0600566 do {
567 switch (peek()) {
568 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600569 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600570 break;
571 case EHTokExtern:
572 // TODO: no meaning in glslang?
573 break;
574 case EHTokShared:
575 // TODO: hint
576 break;
577 case EHTokGroupShared:
578 qualifier.storage = EvqShared;
579 break;
580 case EHTokUniform:
581 qualifier.storage = EvqUniform;
582 break;
583 case EHTokConst:
584 qualifier.storage = EvqConst;
585 break;
586 case EHTokVolatile:
587 qualifier.volatil = true;
588 break;
589 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600590 qualifier.smooth = true;
591 break;
592 case EHTokCentroid:
593 qualifier.centroid = true;
594 break;
595 case EHTokNointerpolation:
596 qualifier.flat = true;
597 break;
598 case EHTokNoperspective:
599 qualifier.nopersp = true;
600 break;
601 case EHTokSample:
602 qualifier.sample = true;
603 break;
604 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600605 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600606 break;
607 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600608 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600609 break;
610 case EHTokPrecise:
611 qualifier.noContraction = true;
612 break;
LoopDawg9249c702016-07-12 20:44:32 -0600613 case EHTokIn:
614 qualifier.storage = EvqIn;
615 break;
616 case EHTokOut:
617 qualifier.storage = EvqOut;
618 break;
619 case EHTokInOut:
620 qualifier.storage = EvqInOut;
621 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600622 case EHTokLayout:
623 if (! acceptLayoutQualifierList(qualifier))
624 return false;
625 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700626 case EHTokGloballyCoherent:
627 qualifier.coherent = true;
628 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700629
630 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
631 // for output variables.
632 case EHTokPoint:
633 qualifier.storage = EvqIn;
634 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
635 return false;
636 break;
637 case EHTokLine:
638 qualifier.storage = EvqIn;
639 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
640 return false;
641 break;
642 case EHTokTriangle:
643 qualifier.storage = EvqIn;
644 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
645 return false;
646 break;
647 case EHTokLineAdj:
648 qualifier.storage = EvqIn;
649 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
650 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700651 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700652 case EHTokTriangleAdj:
653 qualifier.storage = EvqIn;
654 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
655 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700656 break;
657
John Kessenich630dd7d2016-06-12 23:52:12 -0600658 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600659 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600660 }
661 advanceToken();
662 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700663}
664
John Kessenichb9e39122016-08-17 10:22:08 -0600665// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600666// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600667//
668// layout_qualifier
669// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600670// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600671//
672// Zero or more of these, so this can't return false.
673//
674bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
675{
676 if (! acceptTokenClass(EHTokLayout))
677 return false;
678
679 // LEFT_PAREN
680 if (! acceptTokenClass(EHTokLeftParen))
681 return false;
682
683 do {
684 // identifier
685 HlslToken idToken;
686 if (! acceptIdentifier(idToken))
687 break;
688
689 // EQUAL expression
690 if (acceptTokenClass(EHTokAssign)) {
691 TIntermTyped* expr;
692 if (! acceptConditionalExpression(expr)) {
693 expected("expression");
694 return false;
695 }
696 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
697 } else
698 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
699
700 // COMMA
701 if (! acceptTokenClass(EHTokComma))
702 break;
703 } while (true);
704
705 // RIGHT_PAREN
706 if (! acceptTokenClass(EHTokRightParen)) {
707 expected(")");
708 return false;
709 }
710
711 return true;
712}
713
LoopDawg6daaa4f2016-06-23 19:13:48 -0600714// template_type
715// : FLOAT
716// | DOUBLE
717// | INT
718// | DWORD
719// | UINT
720// | BOOL
721//
steve-lunargf49cdf42016-11-17 15:04:20 -0700722bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600723{
724 switch (peek()) {
725 case EHTokFloat:
726 basicType = EbtFloat;
727 break;
728 case EHTokDouble:
729 basicType = EbtDouble;
730 break;
731 case EHTokInt:
732 case EHTokDword:
733 basicType = EbtInt;
734 break;
735 case EHTokUint:
736 basicType = EbtUint;
737 break;
738 case EHTokBool:
739 basicType = EbtBool;
740 break;
741 default:
742 return false;
743 }
744
745 advanceToken();
746
747 return true;
748}
749
750// vector_template_type
751// : VECTOR
752// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
753//
754bool HlslGrammar::acceptVectorTemplateType(TType& type)
755{
756 if (! acceptTokenClass(EHTokVector))
757 return false;
758
759 if (! acceptTokenClass(EHTokLeftAngle)) {
760 // in HLSL, 'vector' alone means float4.
761 new(&type) TType(EbtFloat, EvqTemporary, 4);
762 return true;
763 }
764
765 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700766 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600767 expected("scalar type");
768 return false;
769 }
770
771 // COMMA
772 if (! acceptTokenClass(EHTokComma)) {
773 expected(",");
774 return false;
775 }
776
777 // integer
778 if (! peekTokenClass(EHTokIntConstant)) {
779 expected("literal integer");
780 return false;
781 }
782
783 TIntermTyped* vecSize;
784 if (! acceptLiteral(vecSize))
785 return false;
786
787 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
788
789 new(&type) TType(basicType, EvqTemporary, vecSizeI);
790
791 if (vecSizeI == 1)
792 type.makeVector();
793
794 if (!acceptTokenClass(EHTokRightAngle)) {
795 expected("right angle bracket");
796 return false;
797 }
798
799 return true;
800}
801
802// matrix_template_type
803// : MATRIX
804// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
805//
806bool HlslGrammar::acceptMatrixTemplateType(TType& type)
807{
808 if (! acceptTokenClass(EHTokMatrix))
809 return false;
810
811 if (! acceptTokenClass(EHTokLeftAngle)) {
812 // in HLSL, 'matrix' alone means float4x4.
813 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
814 return true;
815 }
816
817 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700818 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600819 expected("scalar type");
820 return false;
821 }
822
823 // COMMA
824 if (! acceptTokenClass(EHTokComma)) {
825 expected(",");
826 return false;
827 }
828
829 // integer rows
830 if (! peekTokenClass(EHTokIntConstant)) {
831 expected("literal integer");
832 return false;
833 }
834
835 TIntermTyped* rows;
836 if (! acceptLiteral(rows))
837 return false;
838
839 // COMMA
840 if (! acceptTokenClass(EHTokComma)) {
841 expected(",");
842 return false;
843 }
John Kessenichecba76f2017-01-06 00:34:48 -0700844
LoopDawg6daaa4f2016-06-23 19:13:48 -0600845 // integer cols
846 if (! peekTokenClass(EHTokIntConstant)) {
847 expected("literal integer");
848 return false;
849 }
850
851 TIntermTyped* cols;
852 if (! acceptLiteral(cols))
853 return false;
854
855 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600856 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
857 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600858
859 if (!acceptTokenClass(EHTokRightAngle)) {
860 expected("right angle bracket");
861 return false;
862 }
863
864 return true;
865}
866
steve-lunargf49cdf42016-11-17 15:04:20 -0700867// layout_geometry
868// : LINESTREAM
869// | POINTSTREAM
870// | TRIANGLESTREAM
871//
872bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
873{
874 // read geometry type
875 const EHlslTokenClass geometryType = peek();
876
877 switch (geometryType) {
878 case EHTokPointStream: geometry = ElgPoints; break;
879 case EHTokLineStream: geometry = ElgLineStrip; break;
880 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
881 default:
882 return false; // not a layout geometry
883 }
884
885 advanceToken(); // consume the layout keyword
886 return true;
887}
888
steve-lunarg858c9282017-01-07 08:54:10 -0700889// tessellation_decl_type
890// : INPUTPATCH
891// | OUTPUTPATCH
892//
893bool HlslGrammar::acceptTessellationDeclType()
894{
895 // read geometry type
896 const EHlslTokenClass tessType = peek();
897
898 switch (tessType) {
899 case EHTokInputPatch: break;
900 case EHTokOutputPatch: break;
901 default:
902 return false; // not a tessellation decl
903 }
904
905 advanceToken(); // consume the keyword
906 return true;
907}
908
909// tessellation_patch_template_type
910// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
911//
912bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
913{
914 if (! acceptTessellationDeclType())
915 return false;
916
917 if (! acceptTokenClass(EHTokLeftAngle))
918 return false;
919
920 if (! acceptType(type)) {
921 expected("tessellation patch type");
922 return false;
923 }
924
925 if (! acceptTokenClass(EHTokComma))
926 return false;
927
928 // integer size
929 if (! peekTokenClass(EHTokIntConstant)) {
930 expected("literal integer");
931 return false;
932 }
933
934 TIntermTyped* size;
935 if (! acceptLiteral(size))
936 return false;
937
938 TArraySizes* arraySizes = new TArraySizes;
939 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
940 type.newArraySizes(*arraySizes);
941
942 if (! acceptTokenClass(EHTokRightAngle)) {
943 expected("right angle bracket");
944 return false;
945 }
946
947 return true;
948}
949
steve-lunargf49cdf42016-11-17 15:04:20 -0700950// stream_out_template_type
951// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
952//
953bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
954{
955 geometry = ElgNone;
956
957 if (! acceptOutputPrimitiveGeometry(geometry))
958 return false;
959
960 if (! acceptTokenClass(EHTokLeftAngle))
961 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700962
steve-lunargf49cdf42016-11-17 15:04:20 -0700963 if (! acceptType(type)) {
964 expected("stream output type");
965 return false;
966 }
967
968 type.getQualifier().storage = EvqVaryingOut;
969
970 if (! acceptTokenClass(EHTokRightAngle)) {
971 expected("right angle bracket");
972 return false;
973 }
974
975 return true;
976}
John Kessenichecba76f2017-01-06 00:34:48 -0700977
John Kessenicha1e2d492016-09-20 13:22:58 -0600978// annotations
979// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600980//
John Kessenicha1e2d492016-09-20 13:22:58 -0600981bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600982{
John Kessenicha1e2d492016-09-20 13:22:58 -0600983 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600984 return false;
985
John Kessenicha1e2d492016-09-20 13:22:58 -0600986 // note that we are nesting a name space
987 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600988
989 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
990 do {
991 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
992 while (acceptTokenClass(EHTokSemicolon))
993 ;
994
995 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -0600996 break;
John Kessenich86f71382016-09-19 20:23:18 -0600997
998 // declaration
John Kessenichca71d942017-03-07 20:44:09 -0700999 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001000 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001001 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001002 return false;
1003 }
1004 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001005
1006 parseContext.unnestAnnotations();
1007 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001008}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001009
LoopDawg4886f692016-06-29 10:58:58 -06001010// sampler_type
1011// : SAMPLER
1012// | SAMPLER1D
1013// | SAMPLER2D
1014// | SAMPLER3D
1015// | SAMPLERCUBE
1016// | SAMPLERSTATE
1017// | SAMPLERCOMPARISONSTATE
1018bool HlslGrammar::acceptSamplerType(TType& type)
1019{
1020 // read sampler type
1021 const EHlslTokenClass samplerType = peek();
1022
LoopDawga78b0292016-07-19 14:28:05 -06001023 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001024 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001025
LoopDawga78b0292016-07-19 14:28:05 -06001026 bool isShadow = false;
1027
LoopDawg4886f692016-06-29 10:58:58 -06001028 switch (samplerType) {
1029 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001030 case EHTokSampler1d: /*dim = Esd1D*/; break;
1031 case EHTokSampler2d: /*dim = Esd2D*/; break;
1032 case EHTokSampler3d: /*dim = Esd3D*/; break;
1033 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001034 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001035 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001036 default:
1037 return false; // not a sampler declaration
1038 }
1039
1040 advanceToken(); // consume the sampler type keyword
1041
1042 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001043
1044 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001045 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001046
1047 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1048
1049 return true;
1050}
1051
1052// texture_type
1053// | BUFFER
1054// | TEXTURE1D
1055// | TEXTURE1DARRAY
1056// | TEXTURE2D
1057// | TEXTURE2DARRAY
1058// | TEXTURE3D
1059// | TEXTURECUBE
1060// | TEXTURECUBEARRAY
1061// | TEXTURE2DMS
1062// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001063// | RWBUFFER
1064// | RWTEXTURE1D
1065// | RWTEXTURE1DARRAY
1066// | RWTEXTURE2D
1067// | RWTEXTURE2DARRAY
1068// | RWTEXTURE3D
1069
LoopDawg4886f692016-06-29 10:58:58 -06001070bool HlslGrammar::acceptTextureType(TType& type)
1071{
1072 const EHlslTokenClass textureType = peek();
1073
1074 TSamplerDim dim = EsdNone;
1075 bool array = false;
1076 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001077 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -06001078
1079 switch (textureType) {
1080 case EHTokBuffer: dim = EsdBuffer; break;
1081 case EHTokTexture1d: dim = Esd1D; break;
1082 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1083 case EHTokTexture2d: dim = Esd2D; break;
1084 case EHTokTexture2darray: dim = Esd2D; array = true; break;
John Kessenichecba76f2017-01-06 00:34:48 -07001085 case EHTokTexture3d: dim = Esd3D; break;
LoopDawg4886f692016-06-29 10:58:58 -06001086 case EHTokTextureCube: dim = EsdCube; break;
1087 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1088 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1089 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001090 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1091 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1092 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1093 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1094 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1095 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001096 default:
1097 return false; // not a texture declaration
1098 }
1099
1100 advanceToken(); // consume the texture object keyword
1101
1102 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001103
LoopDawg4886f692016-06-29 10:58:58 -06001104 TIntermTyped* msCount = nullptr;
1105
steve-lunargbb0183f2016-10-04 16:58:14 -06001106 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001107 if (acceptTokenClass(EHTokLeftAngle)) {
1108 if (! acceptType(txType)) {
1109 expected("scalar or vector type");
1110 return false;
1111 }
1112
1113 const TBasicType basicRetType = txType.getBasicType() ;
1114
1115 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1116 unimplemented("basic type in texture");
1117 return false;
1118 }
1119
steve-lunargd53f7172016-07-27 15:46:48 -06001120 // Buffers can handle small mats if they fit in 4 components
1121 if (dim == EsdBuffer && txType.isMatrix()) {
1122 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1123 expected("components < 4 in matrix buffer type");
1124 return false;
1125 }
1126
1127 // TODO: except we don't handle it yet...
1128 unimplemented("matrix type in buffer");
1129 return false;
1130 }
1131
LoopDawg4886f692016-06-29 10:58:58 -06001132 if (!txType.isScalar() && !txType.isVector()) {
1133 expected("scalar or vector type");
1134 return false;
1135 }
1136
LoopDawg4886f692016-06-29 10:58:58 -06001137 if (ms && acceptTokenClass(EHTokComma)) {
1138 // read sample count for multisample types, if given
1139 if (! peekTokenClass(EHTokIntConstant)) {
1140 expected("multisample count");
1141 return false;
1142 }
1143
1144 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1145 return false;
1146 }
1147
1148 if (! acceptTokenClass(EHTokRightAngle)) {
1149 expected("right angle bracket");
1150 return false;
1151 }
1152 } else if (ms) {
1153 expected("texture type for multisample");
1154 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001155 } else if (image) {
1156 expected("type for RWTexture/RWBuffer");
1157 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001158 }
1159
1160 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001161 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001162
1163 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001164 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001165
steve-lunarg4f2da272016-10-10 15:24:57 -06001166 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1167 if (image || dim == EsdBuffer)
1168 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001169
1170 // Non-image Buffers are combined
1171 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001172 sampler.set(txType.getBasicType(), dim, array);
1173 } else {
1174 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001175 if (image) {
1176 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1177 } else {
1178 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1179 }
steve-lunargd53f7172016-07-27 15:46:48 -06001180 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001181
1182 // Remember the declared vector size.
1183 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001184
LoopDawg4886f692016-06-29 10:58:58 -06001185 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001186 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001187
1188 return true;
1189}
1190
John Kessenich87142c72016-03-12 20:24:24 -07001191// If token is for a type, update 'type' with the type information,
1192// and return true and advance.
1193// Otherwise, return false, and don't advance
1194bool HlslGrammar::acceptType(TType& type)
1195{
John Kessenich54ee28f2017-03-11 14:13:00 -07001196 TIntermNode* nodeList = nullptr;
1197 return acceptType(type, nodeList);
1198}
1199bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1200{
steve-lunarg3226b082016-10-26 19:18:55 -06001201 // Basic types for min* types, broken out here in case of future
1202 // changes, e.g, to use native halfs.
1203 static const TBasicType min16float_bt = EbtFloat;
1204 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001205 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001206 static const TBasicType min16int_bt = EbtInt;
1207 static const TBasicType min12int_bt = EbtInt;
1208 static const TBasicType min16uint_bt = EbtUint;
1209
John Kessenich9c86c6a2016-05-03 22:49:24 -06001210 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001211 case EHTokVector:
1212 return acceptVectorTemplateType(type);
1213 break;
1214
1215 case EHTokMatrix:
1216 return acceptMatrixTemplateType(type);
1217 break;
1218
steve-lunargf49cdf42016-11-17 15:04:20 -07001219 case EHTokPointStream: // fall through
1220 case EHTokLineStream: // ...
1221 case EHTokTriangleStream: // ...
1222 {
1223 TLayoutGeometry geometry;
1224 if (! acceptStreamOutTemplateType(type, geometry))
1225 return false;
1226
1227 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1228 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001229
steve-lunargf49cdf42016-11-17 15:04:20 -07001230 return true;
1231 }
1232
steve-lunarg858c9282017-01-07 08:54:10 -07001233 case EHTokInputPatch: // fall through
1234 case EHTokOutputPatch: // ...
1235 {
1236 if (! acceptTessellationPatchTemplateType(type))
1237 return false;
1238
1239 return true;
1240 }
1241
LoopDawg4886f692016-06-29 10:58:58 -06001242 case EHTokSampler: // fall through
1243 case EHTokSampler1d: // ...
1244 case EHTokSampler2d: // ...
1245 case EHTokSampler3d: // ...
1246 case EHTokSamplerCube: // ...
1247 case EHTokSamplerState: // ...
1248 case EHTokSamplerComparisonState: // ...
1249 return acceptSamplerType(type);
1250 break;
1251
1252 case EHTokBuffer: // fall through
1253 case EHTokTexture1d: // ...
1254 case EHTokTexture1darray: // ...
1255 case EHTokTexture2d: // ...
1256 case EHTokTexture2darray: // ...
1257 case EHTokTexture3d: // ...
1258 case EHTokTextureCube: // ...
1259 case EHTokTextureCubearray: // ...
1260 case EHTokTexture2DMS: // ...
1261 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001262 case EHTokRWTexture1d: // ...
1263 case EHTokRWTexture1darray: // ...
1264 case EHTokRWTexture2d: // ...
1265 case EHTokRWTexture2darray: // ...
1266 case EHTokRWTexture3d: // ...
1267 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001268 return acceptTextureType(type);
1269 break;
1270
steve-lunarg5da1f032017-02-12 17:50:28 -07001271 case EHTokAppendStructuredBuffer:
1272 case EHTokByteAddressBuffer:
1273 case EHTokConsumeStructuredBuffer:
1274 case EHTokRWByteAddressBuffer:
1275 case EHTokRWStructuredBuffer:
1276 case EHTokStructuredBuffer:
1277 return acceptStructBufferType(type);
1278 break;
1279
John Kessenich27ffb292017-03-03 17:01:01 -07001280 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001281 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001282 case EHTokCBuffer:
1283 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001284 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001285
1286 case EHTokIdentifier:
1287 // An identifier could be for a user-defined type.
1288 // Note we cache the symbol table lookup, to save for a later rule
1289 // when this is not a type.
John Kessenich854fe242017-03-02 14:30:59 -07001290 token.symbol = parseContext.lookupUserType(*token.string, type);
1291 if (token.symbol != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001292 advanceToken();
1293 return true;
1294 } else
1295 return false;
1296
John Kessenich71351de2016-06-08 12:50:56 -06001297 case EHTokVoid:
1298 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001299 break;
John Kessenich71351de2016-06-08 12:50:56 -06001300
John Kessenicha1e2d492016-09-20 13:22:58 -06001301 case EHTokString:
1302 new(&type) TType(EbtString);
1303 break;
1304
John Kessenich87142c72016-03-12 20:24:24 -07001305 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001306 new(&type) TType(EbtFloat);
1307 break;
John Kessenich87142c72016-03-12 20:24:24 -07001308 case EHTokFloat1:
1309 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001310 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001311 break;
John Kessenich87142c72016-03-12 20:24:24 -07001312 case EHTokFloat2:
1313 new(&type) TType(EbtFloat, EvqTemporary, 2);
1314 break;
1315 case EHTokFloat3:
1316 new(&type) TType(EbtFloat, EvqTemporary, 3);
1317 break;
1318 case EHTokFloat4:
1319 new(&type) TType(EbtFloat, EvqTemporary, 4);
1320 break;
1321
John Kessenich71351de2016-06-08 12:50:56 -06001322 case EHTokDouble:
1323 new(&type) TType(EbtDouble);
1324 break;
1325 case EHTokDouble1:
1326 new(&type) TType(EbtDouble);
1327 type.makeVector();
1328 break;
1329 case EHTokDouble2:
1330 new(&type) TType(EbtDouble, EvqTemporary, 2);
1331 break;
1332 case EHTokDouble3:
1333 new(&type) TType(EbtDouble, EvqTemporary, 3);
1334 break;
1335 case EHTokDouble4:
1336 new(&type) TType(EbtDouble, EvqTemporary, 4);
1337 break;
1338
1339 case EHTokInt:
1340 case EHTokDword:
1341 new(&type) TType(EbtInt);
1342 break;
1343 case EHTokInt1:
1344 new(&type) TType(EbtInt);
1345 type.makeVector();
1346 break;
John Kessenich87142c72016-03-12 20:24:24 -07001347 case EHTokInt2:
1348 new(&type) TType(EbtInt, EvqTemporary, 2);
1349 break;
1350 case EHTokInt3:
1351 new(&type) TType(EbtInt, EvqTemporary, 3);
1352 break;
1353 case EHTokInt4:
1354 new(&type) TType(EbtInt, EvqTemporary, 4);
1355 break;
1356
John Kessenich71351de2016-06-08 12:50:56 -06001357 case EHTokUint:
1358 new(&type) TType(EbtUint);
1359 break;
1360 case EHTokUint1:
1361 new(&type) TType(EbtUint);
1362 type.makeVector();
1363 break;
1364 case EHTokUint2:
1365 new(&type) TType(EbtUint, EvqTemporary, 2);
1366 break;
1367 case EHTokUint3:
1368 new(&type) TType(EbtUint, EvqTemporary, 3);
1369 break;
1370 case EHTokUint4:
1371 new(&type) TType(EbtUint, EvqTemporary, 4);
1372 break;
1373
1374 case EHTokBool:
1375 new(&type) TType(EbtBool);
1376 break;
1377 case EHTokBool1:
1378 new(&type) TType(EbtBool);
1379 type.makeVector();
1380 break;
John Kessenich87142c72016-03-12 20:24:24 -07001381 case EHTokBool2:
1382 new(&type) TType(EbtBool, EvqTemporary, 2);
1383 break;
1384 case EHTokBool3:
1385 new(&type) TType(EbtBool, EvqTemporary, 3);
1386 break;
1387 case EHTokBool4:
1388 new(&type) TType(EbtBool, EvqTemporary, 4);
1389 break;
1390
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001391 case EHTokHalf:
1392 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1393 break;
1394 case EHTokHalf1:
1395 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1396 type.makeVector();
1397 break;
1398 case EHTokHalf2:
1399 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1400 break;
1401 case EHTokHalf3:
1402 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1403 break;
1404 case EHTokHalf4:
1405 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1406 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001407
steve-lunarg3226b082016-10-26 19:18:55 -06001408 case EHTokMin16float:
1409 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1410 break;
1411 case EHTokMin16float1:
1412 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1413 type.makeVector();
1414 break;
1415 case EHTokMin16float2:
1416 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1417 break;
1418 case EHTokMin16float3:
1419 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1420 break;
1421 case EHTokMin16float4:
1422 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1423 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001424
steve-lunarg3226b082016-10-26 19:18:55 -06001425 case EHTokMin10float:
1426 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1427 break;
1428 case EHTokMin10float1:
1429 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1430 type.makeVector();
1431 break;
1432 case EHTokMin10float2:
1433 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1434 break;
1435 case EHTokMin10float3:
1436 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1437 break;
1438 case EHTokMin10float4:
1439 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1440 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001441
steve-lunarg3226b082016-10-26 19:18:55 -06001442 case EHTokMin16int:
1443 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1444 break;
1445 case EHTokMin16int1:
1446 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1447 type.makeVector();
1448 break;
1449 case EHTokMin16int2:
1450 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1451 break;
1452 case EHTokMin16int3:
1453 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1454 break;
1455 case EHTokMin16int4:
1456 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1457 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001458
steve-lunarg3226b082016-10-26 19:18:55 -06001459 case EHTokMin12int:
1460 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1461 break;
1462 case EHTokMin12int1:
1463 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1464 type.makeVector();
1465 break;
1466 case EHTokMin12int2:
1467 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1468 break;
1469 case EHTokMin12int3:
1470 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1471 break;
1472 case EHTokMin12int4:
1473 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1474 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001475
steve-lunarg3226b082016-10-26 19:18:55 -06001476 case EHTokMin16uint:
1477 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1478 break;
1479 case EHTokMin16uint1:
1480 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1481 type.makeVector();
1482 break;
1483 case EHTokMin16uint2:
1484 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1485 break;
1486 case EHTokMin16uint3:
1487 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1488 break;
1489 case EHTokMin16uint4:
1490 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1491 break;
1492
John Kessenich0133c122016-05-20 12:17:26 -06001493 case EHTokInt1x1:
1494 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1495 break;
1496 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001497 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001498 break;
1499 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001500 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001501 break;
1502 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001503 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001504 break;
1505 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001506 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001507 break;
1508 case EHTokInt2x2:
1509 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1510 break;
1511 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001512 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001513 break;
1514 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001515 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001516 break;
1517 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001518 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001519 break;
1520 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001521 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001522 break;
1523 case EHTokInt3x3:
1524 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1525 break;
1526 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001527 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001528 break;
1529 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001530 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001531 break;
1532 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001533 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001534 break;
1535 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001536 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001537 break;
1538 case EHTokInt4x4:
1539 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1540 break;
1541
John Kessenich71351de2016-06-08 12:50:56 -06001542 case EHTokUint1x1:
1543 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1544 break;
1545 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001546 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001547 break;
1548 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001549 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001550 break;
1551 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001552 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001553 break;
1554 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001555 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001556 break;
1557 case EHTokUint2x2:
1558 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1559 break;
1560 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001561 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001562 break;
1563 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001564 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001565 break;
1566 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001567 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001568 break;
1569 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001570 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001571 break;
1572 case EHTokUint3x3:
1573 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1574 break;
1575 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001576 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001577 break;
1578 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001579 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001580 break;
1581 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001582 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001583 break;
1584 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001585 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001586 break;
1587 case EHTokUint4x4:
1588 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1589 break;
1590
1591 case EHTokBool1x1:
1592 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1593 break;
1594 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001595 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001596 break;
1597 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001598 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001599 break;
1600 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001601 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001602 break;
1603 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001604 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001605 break;
1606 case EHTokBool2x2:
1607 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1608 break;
1609 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001610 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001611 break;
1612 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001613 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001614 break;
1615 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001616 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001617 break;
1618 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001619 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001620 break;
1621 case EHTokBool3x3:
1622 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1623 break;
1624 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001625 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001626 break;
1627 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001628 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001629 break;
1630 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001631 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001632 break;
1633 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001634 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001635 break;
1636 case EHTokBool4x4:
1637 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1638 break;
1639
John Kessenich0133c122016-05-20 12:17:26 -06001640 case EHTokFloat1x1:
1641 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1642 break;
1643 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001644 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001645 break;
1646 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001647 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001648 break;
1649 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001650 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001651 break;
1652 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001653 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001654 break;
John Kessenich87142c72016-03-12 20:24:24 -07001655 case EHTokFloat2x2:
1656 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1657 break;
1658 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001659 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001660 break;
1661 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001662 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001663 break;
John Kessenich0133c122016-05-20 12:17:26 -06001664 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001665 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001666 break;
John Kessenich87142c72016-03-12 20:24:24 -07001667 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001668 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001669 break;
1670 case EHTokFloat3x3:
1671 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1672 break;
1673 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001674 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001675 break;
John Kessenich0133c122016-05-20 12:17:26 -06001676 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001677 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001678 break;
John Kessenich87142c72016-03-12 20:24:24 -07001679 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001680 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001681 break;
1682 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001683 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001684 break;
1685 case EHTokFloat4x4:
1686 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1687 break;
1688
John Kessenich0133c122016-05-20 12:17:26 -06001689 case EHTokDouble1x1:
1690 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1691 break;
1692 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001693 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001694 break;
1695 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001696 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001697 break;
1698 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001699 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001700 break;
1701 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001702 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001703 break;
1704 case EHTokDouble2x2:
1705 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1706 break;
1707 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001708 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001709 break;
1710 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001711 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001712 break;
1713 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001714 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001715 break;
1716 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001717 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001718 break;
1719 case EHTokDouble3x3:
1720 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1721 break;
1722 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001723 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001724 break;
1725 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001726 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001727 break;
1728 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001729 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001730 break;
1731 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001732 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001733 break;
1734 case EHTokDouble4x4:
1735 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1736 break;
1737
John Kessenich87142c72016-03-12 20:24:24 -07001738 default:
1739 return false;
1740 }
1741
1742 advanceToken();
1743
1744 return true;
1745}
1746
John Kesseniche6e74942016-06-11 16:43:14 -06001747// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001748// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1749// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001750// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001751//
1752// struct_type
1753// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001754// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001755// | CBUFFER
1756// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001757//
John Kessenich54ee28f2017-03-11 14:13:00 -07001758bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001759{
John Kessenichb804de62016-09-05 12:19:18 -06001760 // This storage qualifier will tell us whether it's an AST
1761 // block type or just a generic structure type.
1762 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001763
1764 // CBUFFER
1765 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001766 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001767 // TBUFFER
1768 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001769 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001770 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001771 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001772 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001773 return false;
1774
1775 // IDENTIFIER
1776 TString structName = "";
1777 if (peekTokenClass(EHTokIdentifier)) {
1778 structName = *token.string;
1779 advanceToken();
1780 }
1781
John Kessenich3d157c52016-07-25 16:05:33 -06001782 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001783 TQualifier postDeclQualifier;
1784 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001785 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001786
John Kesseniche6e74942016-06-11 16:43:14 -06001787 // LEFT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001788 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001789 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001790 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1791 // struct_type IDENTIFIER
1792 return true;
1793 } else {
1794 expected("{");
1795 return false;
1796 }
John Kesseniche6e74942016-06-11 16:43:14 -06001797 }
1798
1799 // struct_declaration_list
1800 TTypeList* typeList;
John Kessenich54ee28f2017-03-11 14:13:00 -07001801 if (! acceptStructDeclarationList(typeList, nodeList, structName)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001802 expected("struct member declarations");
1803 return false;
1804 }
1805
1806 // RIGHT_BRACE
1807 if (! acceptTokenClass(EHTokRightBrace)) {
1808 expected("}");
1809 return false;
1810 }
1811
1812 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001813 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001814 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001815 else {
John Kessenich7735b942016-09-05 12:40:06 -06001816 postDeclQualifier.storage = storageQualifier;
1817 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001818 }
John Kesseniche6e74942016-06-11 16:43:14 -06001819
John Kessenich727b3742017-02-03 17:57:55 -07001820 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001821
1822 return true;
1823}
1824
steve-lunarg5da1f032017-02-12 17:50:28 -07001825// struct_buffer
1826// : APPENDSTRUCTUREDBUFFER
1827// | BYTEADDRESSBUFFER
1828// | CONSUMESTRUCTUREDBUFFER
1829// | RWBYTEADDRESSBUFFER
1830// | RWSTRUCTUREDBUFFER
1831// | STRUCTUREDBUFFER
1832bool HlslGrammar::acceptStructBufferType(TType& type)
1833{
1834 const EHlslTokenClass structBuffType = peek();
1835
1836 // TODO: globallycoherent
1837 bool hasTemplateType = true;
1838 bool readonly = false;
1839
1840 TStorageQualifier storage = EvqBuffer;
1841
1842 switch (structBuffType) {
1843 case EHTokAppendStructuredBuffer:
1844 unimplemented("AppendStructuredBuffer");
1845 return false;
1846 case EHTokByteAddressBuffer:
1847 hasTemplateType = false;
1848 readonly = true;
1849 break;
1850 case EHTokConsumeStructuredBuffer:
1851 unimplemented("ConsumeStructuredBuffer");
1852 return false;
1853 case EHTokRWByteAddressBuffer:
1854 hasTemplateType = false;
1855 break;
1856 case EHTokRWStructuredBuffer:
1857 break;
1858 case EHTokStructuredBuffer:
1859 readonly = true;
1860 break;
1861 default:
1862 return false; // not a structure buffer type
1863 }
1864
1865 advanceToken(); // consume the structure keyword
1866
1867 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1868 TType* templateType = new TType;
1869
1870 if (hasTemplateType) {
1871 if (! acceptTokenClass(EHTokLeftAngle)) {
1872 expected("left angle bracket");
1873 return false;
1874 }
1875
1876 if (! acceptType(*templateType)) {
1877 expected("type");
1878 return false;
1879 }
1880 if (! acceptTokenClass(EHTokRightAngle)) {
1881 expected("right angle bracket");
1882 return false;
1883 }
1884 } else {
1885 // byte address buffers have no explicit type.
1886 TType uintType(EbtUint, storage);
1887 templateType->shallowCopy(uintType);
1888 }
1889
1890 // Create an unsized array out of that type.
1891 // TODO: does this work if it's already an array type?
1892 TArraySizes unsizedArray;
1893 unsizedArray.addInnerSize(UnsizedArraySize);
1894 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07001895 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07001896
1897 // field name is canonical for all structbuffers
1898 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07001899
1900 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07001901
steve-lunarg5da1f032017-02-12 17:50:28 -07001902 TTypeList* blockStruct = new TTypeList;
1903 TTypeLoc member = { templateType, token.loc };
1904 blockStruct->push_back(member);
1905
steve-lunargdd8287a2017-02-23 18:04:12 -07001906 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07001907 TType blockType(blockStruct, "", templateType->getQualifier());
1908
steve-lunargdd8287a2017-02-23 18:04:12 -07001909 blockType.getQualifier().storage = storage;
1910 blockType.getQualifier().readonly = readonly;
1911
1912 // We may have created an equivalent type before, in which case we should use its
1913 // deep structure.
1914 parseContext.shareStructBufferType(blockType);
1915
steve-lunarg5da1f032017-02-12 17:50:28 -07001916 type.shallowCopy(blockType);
1917
1918 return true;
1919}
1920
John Kesseniche6e74942016-06-11 16:43:14 -06001921// struct_declaration_list
1922// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1923//
1924// struct_declaration
1925// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001926// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06001927//
1928// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001929// : IDENTIFIER post_decls
1930// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07001931// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06001932//
John Kessenich54ee28f2017-03-11 14:13:00 -07001933bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, const TString& typeName)
John Kesseniche6e74942016-06-11 16:43:14 -06001934{
1935 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001936 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001937
1938 do {
1939 // success on seeing the RIGHT_BRACE coming up
1940 if (peekTokenClass(EHTokRightBrace))
1941 return true;
1942
1943 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07001944
1945 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001946
1947 // fully_specified_type
1948 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07001949 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001950 expected("member type");
1951 return false;
1952 }
1953
1954 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001955 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001956 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001957 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001958 expected("member name");
1959 return false;
1960 }
1961
John Kessenich54ee28f2017-03-11 14:13:00 -07001962 if (peekTokenClass(EHTokLeftParen)) {
1963 // function_parameters
1964 if (!declarator_list) {
1965 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, typeName, memberType, *idToken.string);
1966 if (functionDefinitionAccepted)
1967 break;
1968 }
1969 expected("member-function definition");
1970 return false;
1971 } else {
1972 // add it to the list of members
1973 TTypeLoc member = { new TType(EbtVoid), token.loc };
1974 member.type->shallowCopy(memberType);
1975 member.type->setFieldName(*idToken.string);
1976 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06001977
John Kessenich54ee28f2017-03-11 14:13:00 -07001978 // array_specifier
1979 TArraySizes* arraySizes = nullptr;
1980 acceptArraySpecifier(arraySizes);
1981 if (arraySizes)
1982 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001983
John Kessenich54ee28f2017-03-11 14:13:00 -07001984 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06001985
John Kessenich54ee28f2017-03-11 14:13:00 -07001986 // EQUAL assignment_expression
1987 if (acceptTokenClass(EHTokAssign)) {
1988 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
1989 TIntermTyped* expressionNode = nullptr;
1990 if (! acceptAssignmentExpression(expressionNode)) {
1991 expected("initializer");
1992 return false;
1993 }
John Kessenich18adbdb2017-02-02 15:16:20 -07001994 }
1995 }
John Kesseniche6e74942016-06-11 16:43:14 -06001996 // success on seeing the SEMICOLON coming up
1997 if (peekTokenClass(EHTokSemicolon))
1998 break;
1999
2000 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002001 if (acceptTokenClass(EHTokComma))
2002 declarator_list = true;
2003 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002004 expected(",");
2005 return false;
2006 }
2007
2008 } while (true);
2009
2010 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002011 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002012 expected(";");
2013 return false;
2014 }
2015
2016 } while (true);
2017}
2018
John Kessenich54ee28f2017-03-11 14:13:00 -07002019// member_function_definition
2020// | function_parameters post_decls compound_statement
2021//
2022// Expects type to have EvqGlobal for a static member and
2023// EvqTemporary for non-static member.
2024bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName,
2025 const TType& type, const TString& memberName)
2026{
2027 // watch early returns...
2028 parseContext.pushThis(typeName);
2029 bool accepted = false;
2030
2031 TString* functionName = parseContext.getFullMemberFunctionName(memberName, type.getQualifier().storage == EvqGlobal);
2032 TFunction& function = *new TFunction(functionName, type);
2033
2034 // function_parameters
2035 if (acceptFunctionParameters(function)) {
2036 // post_decls
2037 acceptPostDecls(function.getWritableType().getQualifier());
2038
2039 // compound_statement (function body definition)
2040 if (peekTokenClass(EHTokLeftBrace)) {
2041 if (function.getType().getQualifier().storage != EvqGlobal) {
2042 expected("only static member functions are accepted");
2043 return false;
2044 }
2045
2046 TAttributeMap attributes;
2047 accepted = acceptFunctionDefinition(function, nodeList, attributes);
2048 }
2049 } else
2050 expected("function parameter list");
2051
2052 parseContext.popThis();
2053 return accepted;
2054}
2055
John Kessenich5f934b02016-03-13 17:58:25 -06002056// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002057// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002058// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002059//
2060bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2061{
John Kessenich078d7f22016-03-14 10:02:11 -06002062 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002063 if (! acceptTokenClass(EHTokLeftParen))
2064 return false;
2065
John Kessenich71351de2016-06-08 12:50:56 -06002066 // VOID RIGHT_PAREN
2067 if (! acceptTokenClass(EHTokVoid)) {
2068 do {
2069 // parameter_declaration
2070 if (! acceptParameterDeclaration(function))
2071 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002072
John Kessenich71351de2016-06-08 12:50:56 -06002073 // COMMA
2074 if (! acceptTokenClass(EHTokComma))
2075 break;
2076 } while (true);
2077 }
John Kessenich5f934b02016-03-13 17:58:25 -06002078
John Kessenich078d7f22016-03-14 10:02:11 -06002079 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002080 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002081 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002082 return false;
2083 }
2084
2085 return true;
2086}
2087
steve-lunarg26d31452016-12-23 18:56:57 -07002088// default_parameter_declaration
2089// : EQUAL conditional_expression
2090// : EQUAL initializer
2091bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2092{
2093 node = nullptr;
2094
2095 // Valid not to have a default_parameter_declaration
2096 if (!acceptTokenClass(EHTokAssign))
2097 return true;
2098
2099 if (!acceptConditionalExpression(node)) {
2100 if (!acceptInitializer(node))
2101 return false;
2102
2103 // For initializer lists, we have to const-fold into a constructor for the type, so build
2104 // that.
2105 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2106 if (constructor == nullptr) // cannot construct
2107 return false;
2108
2109 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002110 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002111 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002112
steve-lunarg26d31452016-12-23 18:56:57 -07002113 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2114 }
2115
2116 // If this is simply a constant, we can use it directly.
2117 if (node->getAsConstantUnion())
2118 return true;
2119
2120 // Otherwise, it has to be const-foldable.
2121 TIntermTyped* origNode = node;
2122
2123 node = intermediate.fold(node->getAsAggregate());
2124
2125 if (node != nullptr && origNode != node)
2126 return true;
2127
2128 parseContext.error(token.loc, "invalid default parameter value", "", "");
2129
2130 return false;
2131}
2132
John Kessenich5f934b02016-03-13 17:58:25 -06002133// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002134// : fully_specified_type post_decls [ = default_parameter_declaration ]
2135// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002136//
2137bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2138{
2139 // fully_specified_type
2140 TType* type = new TType;
2141 if (! acceptFullySpecifiedType(*type))
2142 return false;
2143
2144 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002145 HlslToken idToken;
2146 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002147
John Kessenich19b92ff2016-06-19 11:50:34 -06002148 // array_specifier
2149 TArraySizes* arraySizes = nullptr;
2150 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002151 if (arraySizes) {
2152 if (arraySizes->isImplicit()) {
2153 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2154 return false;
2155 }
2156
John Kessenich19b92ff2016-06-19 11:50:34 -06002157 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002158 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002159
2160 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002161 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002162
steve-lunarg26d31452016-12-23 18:56:57 -07002163 TIntermTyped* defaultValue;
2164 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2165 return false;
2166
John Kessenich5aa59e22016-06-17 15:50:47 -06002167 parseContext.paramFix(*type);
2168
steve-lunarg26d31452016-12-23 18:56:57 -07002169 // If any prior parameters have default values, all the parameters after that must as well.
2170 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2171 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2172 return false;
2173 }
2174
2175 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002176 function.addParameter(param);
2177
2178 return true;
2179}
2180
2181// Do the work to create the function definition in addition to
2182// parsing the body (compound_statement).
John Kessenichca71d942017-03-07 20:44:09 -07002183bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& nodeList, const TAttributeMap& attributes)
John Kessenich5f934b02016-03-13 17:58:25 -06002184{
John Kessenicha3051662016-09-02 19:13:36 -06002185 TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
John Kessenich1a4b7752016-09-02 19:05:24 -06002186 TSourceLoc loc = token.loc;
John Kessenich5f934b02016-03-13 17:58:25 -06002187
John Kessenichca71d942017-03-07 20:44:09 -07002188 // we might get back and entry-point
2189 TIntermNode* entryPointNode = nullptr;
2190
John Kessenich077e0522016-06-09 02:02:17 -06002191 // This does a pushScope()
John Kessenichca71d942017-03-07 20:44:09 -07002192 TIntermNode* functionNode = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes,
2193 entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002194
2195 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002196 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002197 if (! acceptCompoundStatement(functionBody))
2198 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002199
John Kessenich54ee28f2017-03-11 14:13:00 -07002200 // this does a popScope()
John Kessenichca71d942017-03-07 20:44:09 -07002201 parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, functionNode);
2202
2203 // Hook up the 1 or 2 function definitions.
2204 nodeList = intermediate.growAggregate(nodeList, functionNode);
2205 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002206
2207 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002208}
2209
John Kessenich0d2b6de2016-06-05 11:23:11 -06002210// Accept an expression with parenthesis around it, where
2211// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002212// syntactically required ones like in "if ( expression )".
2213//
2214// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002215//
2216// Note this one is not set up to be speculative; as it gives
2217// errors if not found.
2218//
2219bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2220{
2221 // LEFT_PAREN
2222 if (! acceptTokenClass(EHTokLeftParen))
2223 expected("(");
2224
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002225 bool decl = false;
2226 TIntermNode* declNode = nullptr;
2227 decl = acceptControlDeclaration(declNode);
2228 if (decl) {
2229 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2230 expected("initialized declaration");
2231 return false;
2232 } else
2233 expression = declNode->getAsTyped();
2234 } else {
2235 // no declaration
2236 if (! acceptExpression(expression)) {
2237 expected("expression");
2238 return false;
2239 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002240 }
2241
2242 // RIGHT_PAREN
2243 if (! acceptTokenClass(EHTokRightParen))
2244 expected(")");
2245
2246 return true;
2247}
2248
John Kessenich34fb0362016-05-03 23:17:20 -06002249// The top-level full expression recognizer.
2250//
John Kessenich87142c72016-03-12 20:24:24 -07002251// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002252// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002253//
2254bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2255{
LoopDawgef764a22016-06-03 09:17:51 -06002256 node = nullptr;
2257
John Kessenich34fb0362016-05-03 23:17:20 -06002258 // assignment_expression
2259 if (! acceptAssignmentExpression(node))
2260 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002261
John Kessenich34fb0362016-05-03 23:17:20 -06002262 if (! peekTokenClass(EHTokComma))
2263 return true;
2264
2265 do {
2266 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002267 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002268 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002269
John Kessenich34fb0362016-05-03 23:17:20 -06002270 // ... assignment_expression
2271 TIntermTyped* rightNode = nullptr;
2272 if (! acceptAssignmentExpression(rightNode)) {
2273 expected("assignment expression");
2274 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002275 }
2276
John Kessenich34fb0362016-05-03 23:17:20 -06002277 node = intermediate.addComma(node, rightNode, loc);
2278
2279 if (! peekTokenClass(EHTokComma))
2280 return true;
2281 } while (true);
2282}
2283
John Kessenich07354242016-07-01 19:58:06 -06002284// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002285// : LEFT_BRACE RIGHT_BRACE
2286// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002287//
2288// initializer_list
2289// : assignment_expression COMMA assignment_expression COMMA ...
2290//
2291bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2292{
2293 // LEFT_BRACE
2294 if (! acceptTokenClass(EHTokLeftBrace))
2295 return false;
2296
John Kessenich98ad4852016-11-27 17:39:07 -07002297 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002298 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002299 if (acceptTokenClass(EHTokRightBrace)) {
2300 // a zero-length initializer list
2301 node = intermediate.makeAggregate(loc);
2302 return true;
2303 }
2304
2305 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002306 node = nullptr;
2307 do {
2308 // assignment_expression
2309 TIntermTyped* expr;
2310 if (! acceptAssignmentExpression(expr)) {
2311 expected("assignment expression in initializer list");
2312 return false;
2313 }
2314 node = intermediate.growAggregate(node, expr, loc);
2315
2316 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002317 if (acceptTokenClass(EHTokComma)) {
2318 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2319 return true;
John Kessenich07354242016-07-01 19:58:06 -06002320 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002321 }
John Kessenich07354242016-07-01 19:58:06 -06002322
2323 // RIGHT_BRACE
2324 if (acceptTokenClass(EHTokRightBrace))
2325 return true;
2326
2327 expected(", or }");
2328 return false;
2329 } while (true);
2330}
2331
John Kessenich34fb0362016-05-03 23:17:20 -06002332// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002333// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002334//
2335// a op (b op (c op d))
2336//
2337// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002338// : initializer
2339// | conditional_expression
2340// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002341//
2342bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2343{
John Kessenich07354242016-07-01 19:58:06 -06002344 // initializer
2345 if (peekTokenClass(EHTokLeftBrace)) {
2346 if (acceptInitializer(node))
2347 return true;
2348
2349 expected("initializer");
2350 return false;
2351 }
2352
John Kessenich00957f82016-07-27 10:39:57 -06002353 // conditional_expression
2354 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002355 return false;
2356
John Kessenich07354242016-07-01 19:58:06 -06002357 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002358 TOperator assignOp = HlslOpMap::assignment(peek());
2359 if (assignOp == EOpNull)
2360 return true;
2361
John Kessenich00957f82016-07-27 10:39:57 -06002362 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002363 TSourceLoc loc = token.loc;
2364 advanceToken();
2365
John Kessenich00957f82016-07-27 10:39:57 -06002366 // conditional_expression assign_op conditional_expression ...
2367 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002368 // gets the right-to-left associativity.
2369 TIntermTyped* rightNode = nullptr;
2370 if (! acceptAssignmentExpression(rightNode)) {
2371 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002372 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002373 }
2374
John Kessenichd21baed2016-09-16 03:05:12 -06002375 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002376 node = parseContext.handleLvalue(loc, "assign", node);
2377
John Kessenichfea226b2016-07-28 17:53:56 -06002378 if (node == nullptr) {
2379 parseContext.error(loc, "could not create assignment", "", "");
2380 return false;
2381 }
John Kessenich34fb0362016-05-03 23:17:20 -06002382
2383 if (! peekTokenClass(EHTokComma))
2384 return true;
2385
2386 return true;
2387}
2388
John Kessenich00957f82016-07-27 10:39:57 -06002389// Accept a conditional expression, which associates right-to-left,
2390// accomplished by the "true" expression calling down to lower
2391// precedence levels than this level.
2392//
2393// conditional_expression
2394// : binary_expression
2395// | binary_expression QUESTION expression COLON assignment_expression
2396//
2397bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2398{
2399 // binary_expression
2400 if (! acceptBinaryExpression(node, PlLogicalOr))
2401 return false;
2402
2403 if (! acceptTokenClass(EHTokQuestion))
2404 return true;
2405
2406 TIntermTyped* trueNode = nullptr;
2407 if (! acceptExpression(trueNode)) {
2408 expected("expression after ?");
2409 return false;
2410 }
2411 TSourceLoc loc = token.loc;
2412
2413 if (! acceptTokenClass(EHTokColon)) {
2414 expected(":");
2415 return false;
2416 }
2417
2418 TIntermTyped* falseNode = nullptr;
2419 if (! acceptAssignmentExpression(falseNode)) {
2420 expected("expression after :");
2421 return false;
2422 }
2423
2424 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2425
2426 return true;
2427}
2428
John Kessenich34fb0362016-05-03 23:17:20 -06002429// Accept a binary expression, for binary operations that
2430// associate left-to-right. This is, it is implicit, for example
2431//
2432// ((a op b) op c) op d
2433//
2434// binary_expression
2435// : expression op expression op expression ...
2436//
2437// where 'expression' is the next higher level in precedence.
2438//
2439bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2440{
2441 if (precedenceLevel > PlMul)
2442 return acceptUnaryExpression(node);
2443
2444 // assignment_expression
2445 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2446 return false;
2447
John Kessenich34fb0362016-05-03 23:17:20 -06002448 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002449 TOperator op = HlslOpMap::binary(peek());
2450 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2451 if (tokenLevel < precedenceLevel)
2452 return true;
2453
John Kessenich34fb0362016-05-03 23:17:20 -06002454 // ... op
2455 TSourceLoc loc = token.loc;
2456 advanceToken();
2457
2458 // ... expression
2459 TIntermTyped* rightNode = nullptr;
2460 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2461 expected("expression");
2462 return false;
2463 }
2464
2465 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002466 if (node == nullptr) {
2467 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2468 return false;
2469 }
John Kessenich34fb0362016-05-03 23:17:20 -06002470 } while (true);
2471}
2472
2473// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002474// : (type) unary_expression
2475// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002476// | - unary_expression
2477// | ! unary_expression
2478// | ~ unary_expression
2479// | ++ unary_expression
2480// | -- unary_expression
2481// | postfix_expression
2482//
2483bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2484{
John Kessenich1cc1a282016-06-03 16:55:49 -06002485 // (type) unary_expression
2486 // Have to look two steps ahead, because this could be, e.g., a
2487 // postfix_expression instead, since that also starts with at "(".
2488 if (acceptTokenClass(EHTokLeftParen)) {
2489 TType castType;
2490 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002491 if (acceptTokenClass(EHTokRightParen)) {
2492 // We've matched "(type)" now, get the expression to cast
2493 TSourceLoc loc = token.loc;
2494 if (! acceptUnaryExpression(node))
2495 return false;
2496
2497 // Hook it up like a constructor
2498 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2499 if (constructorFunction == nullptr) {
2500 expected("type that can be constructed");
2501 return false;
2502 }
2503 TIntermTyped* arguments = nullptr;
2504 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2505 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2506
2507 return true;
2508 } else {
2509 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2510 // the '(int' part. We must back up twice.
2511 recedeToken();
2512 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002513 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002514 } else {
2515 // This isn't a type cast, but it still started "(", so if it is a
2516 // unary expression, it can only be a postfix_expression, so try that.
2517 // Back it up first.
2518 recedeToken();
2519 return acceptPostfixExpression(node);
2520 }
2521 }
2522
2523 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002524 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002525
John Kessenich1cc1a282016-06-03 16:55:49 -06002526 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002527 if (unaryOp == EOpNull)
2528 return acceptPostfixExpression(node);
2529
2530 // op unary_expression
2531 TSourceLoc loc = token.loc;
2532 advanceToken();
2533 if (! acceptUnaryExpression(node))
2534 return false;
2535
2536 // + is a no-op
2537 if (unaryOp == EOpAdd)
2538 return true;
2539
2540 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002541
2542 // These unary ops require lvalues
2543 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2544 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002545
2546 return node != nullptr;
2547}
2548
2549// postfix_expression
2550// : LEFT_PAREN expression RIGHT_PAREN
2551// | literal
2552// | constructor
2553// | identifier
2554// | function_call
2555// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2556// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002557// | postfix_expression DOT IDENTIFIER arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002558// | postfix_expression COLONCOLON IDENTIFIER arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002559// | postfix_expression INC_OP
2560// | postfix_expression DEC_OP
2561//
2562bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2563{
2564 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002565 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002566
2567 // idToken will pick up either a variable or a function name in a function call
2568 HlslToken idToken;
2569
John Kessenich54ee28f2017-03-11 14:13:00 -07002570 // scopeBase will pick up the type symbol on the left of '::'
2571 TSymbol* scopeBase = nullptr;
2572
John Kessenich21472ae2016-06-04 11:46:33 -06002573 // Find something before the postfix operations, as they can't operate
2574 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002575 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002576 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002577 if (! acceptExpression(node)) {
2578 expected("expression");
2579 return false;
2580 }
2581 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002582 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002583 return false;
2584 }
John Kessenich34fb0362016-05-03 23:17:20 -06002585 } else if (acceptLiteral(node)) {
John Kessenichecba76f2017-01-06 00:34:48 -07002586 // literal (nothing else to do yet), go on to the
John Kessenich34fb0362016-05-03 23:17:20 -06002587 } else if (acceptConstructor(node)) {
2588 // constructor (nothing else to do yet)
2589 } else if (acceptIdentifier(idToken)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002590 // user-type, identifier, or function name
2591 if (peekTokenClass(EHTokColonColon)) {
2592 TType type;
2593 scopeBase = parseContext.lookupUserType(*idToken.string, type);
2594 if (scopeBase == nullptr) {
2595 expected("type left of ::");
2596 return false;
2597 }
2598 } else if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002599 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002600 } else if (acceptFunctionCall(idToken, node)) {
2601 // function_call (nothing else to do yet)
2602 } else {
2603 expected("function call arguments");
2604 return false;
2605 }
John Kessenich21472ae2016-06-04 11:46:33 -06002606 } else {
2607 // nothing found, can't post operate
2608 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002609 }
2610
steve-lunarga2b01a02016-11-28 17:09:54 -07002611 // This is to guarantee we do this no matter how we get out of the stack frame.
2612 // This way there's no bug if an early return forgets to do it.
2613 struct tFinalize {
2614 tFinalize(HlslParseContext& p) : parseContext(p) { }
2615 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002616 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002617 private:
John Kessenichca71d942017-03-07 20:44:09 -07002618 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002619 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002620 } finalize(parseContext);
2621
2622 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2623 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2624 // level: hence the init and finalize. Even though in practice these must be
2625 // constants, they are parsed no matter what.
2626 parseContext.initFlattening();
2627
John Kessenich21472ae2016-06-04 11:46:33 -06002628 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002629 do {
2630 TSourceLoc loc = token.loc;
2631 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002632
John Kessenich34fb0362016-05-03 23:17:20 -06002633 // Consume only a valid post-unary operator, otherwise we are done.
2634 switch (postOp) {
2635 case EOpIndexDirectStruct:
2636 case EOpIndexIndirect:
2637 case EOpPostIncrement:
2638 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002639 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002640 advanceToken();
2641 break;
2642 default:
2643 return true;
2644 }
John Kessenich87142c72016-03-12 20:24:24 -07002645
John Kessenich34fb0362016-05-03 23:17:20 -06002646 // We have a valid post-unary operator, process it.
2647 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002648 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002649 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002650 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002651 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002652 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002653 HlslToken field;
2654 if (! acceptIdentifier(field)) {
2655 expected("swizzle or member");
2656 return false;
2657 }
LoopDawg4886f692016-06-29 10:58:58 -06002658
John Kessenich516d92d2017-03-08 20:09:03 -07002659 if (peekTokenClass(EHTokLeftParen)) {
2660 // member function
2661 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002662
John Kessenich516d92d2017-03-08 20:09:03 -07002663 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002664 if (! acceptFunctionCall(field, node, thisNode, scopeBase)) {
LoopDawg4886f692016-06-29 10:58:58 -06002665 expected("function parameters");
2666 return false;
2667 }
John Kessenich516d92d2017-03-08 20:09:03 -07002668 } else
2669 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002670
John Kessenich34fb0362016-05-03 23:17:20 -06002671 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002672 }
John Kessenich34fb0362016-05-03 23:17:20 -06002673 case EOpIndexIndirect:
2674 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002675 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002676 TIntermTyped* indexNode = nullptr;
2677 if (! acceptExpression(indexNode) ||
2678 ! peekTokenClass(EHTokRightBracket)) {
2679 expected("expression followed by ']'");
2680 return false;
2681 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002682 advanceToken();
2683 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2684 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002685 }
2686 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002687 // INC_OP
2688 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002689 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002690 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002691 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002692 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002693 break;
2694 default:
2695 assert(0);
2696 break;
2697 }
2698 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002699}
2700
John Kessenichd016be12016-03-13 11:24:20 -06002701// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002702// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002703//
2704bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2705{
2706 // type
2707 TType type;
2708 if (acceptType(type)) {
2709 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2710 if (constructorFunction == nullptr)
2711 return false;
2712
2713 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002714 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002715 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002716 // It's possible this is a type keyword used as an identifier. Put the token back
2717 // for later use.
2718 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002719 return false;
2720 }
2721
2722 // hook it up
2723 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2724
2725 return true;
2726 }
2727
2728 return false;
2729}
2730
John Kessenich34fb0362016-05-03 23:17:20 -06002731// The function_call identifier was already recognized, and passed in as idToken.
2732//
2733// function_call
2734// : [idToken] arguments
2735//
John Kessenich54ee28f2017-03-11 14:13:00 -07002736bool HlslGrammar::acceptFunctionCall(HlslToken callToken, TIntermTyped*& node, TIntermTyped* baseObject,
2737 const TSymbol* baseType)
John Kessenich34fb0362016-05-03 23:17:20 -06002738{
John Kessenich54ee28f2017-03-11 14:13:00 -07002739 // name
2740 TString* functionName = nullptr;
2741 if ((baseObject == nullptr && baseType == nullptr)
2742 || parseContext.isBuiltInMethod(callToken.loc, baseObject, *callToken.string))
2743 functionName = callToken.string;
2744 else {
2745 functionName = NewPoolTString("");
2746 if (baseObject != nullptr) {
2747 functionName->append(baseObject->getType().getTypeName().c_str());
2748 functionName->append(".");
2749 } else if (baseType != nullptr) {
2750 functionName->append(baseType->getType().getTypeName());
2751 functionName->append("::");
John Kessenich5f12d2f2017-03-11 09:39:55 -07002752 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002753 functionName->append(*callToken.string);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002754 }
LoopDawg4886f692016-06-29 10:58:58 -06002755
John Kessenich54ee28f2017-03-11 14:13:00 -07002756 // function
2757 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2758
2759 // arguments
2760 // Non-static member functions have an implicit first argument of the base object.
2761 TIntermTyped* arguments = nullptr;
2762 if (baseObject != nullptr)
2763 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenich4678ca92016-05-13 09:33:42 -06002764 if (! acceptArguments(function, arguments))
2765 return false;
2766
John Kessenich54ee28f2017-03-11 14:13:00 -07002767 // call
John Kessenich5f12d2f2017-03-11 09:39:55 -07002768 node = parseContext.handleFunctionCall(callToken.loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002769
2770 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002771}
2772
John Kessenich87142c72016-03-12 20:24:24 -07002773// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002774// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002775//
John Kessenichd016be12016-03-13 11:24:20 -06002776// The arguments are pushed onto the 'function' argument list and
2777// onto the 'arguments' aggregate.
2778//
John Kessenich4678ca92016-05-13 09:33:42 -06002779bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002780{
John Kessenich078d7f22016-03-14 10:02:11 -06002781 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002782 if (! acceptTokenClass(EHTokLeftParen))
2783 return false;
2784
2785 do {
John Kessenichd016be12016-03-13 11:24:20 -06002786 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002787 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002788 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002789 break;
John Kessenichd016be12016-03-13 11:24:20 -06002790
2791 // hook it up
2792 parseContext.handleFunctionArgument(function, arguments, arg);
2793
John Kessenich078d7f22016-03-14 10:02:11 -06002794 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002795 if (! acceptTokenClass(EHTokComma))
2796 break;
2797 } while (true);
2798
John Kessenich078d7f22016-03-14 10:02:11 -06002799 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002800 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002801 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002802 return false;
2803 }
2804
2805 return true;
2806}
2807
2808bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2809{
2810 switch (token.tokenClass) {
2811 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002812 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002813 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002814 case EHTokUintConstant:
2815 node = intermediate.addConstantUnion(token.u, token.loc, true);
2816 break;
John Kessenich87142c72016-03-12 20:24:24 -07002817 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002818 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002819 break;
2820 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002821 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002822 break;
2823 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002824 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002825 break;
John Kessenich86f71382016-09-19 20:23:18 -06002826 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002827 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002828 break;
John Kessenich87142c72016-03-12 20:24:24 -07002829
2830 default:
2831 return false;
2832 }
2833
2834 advanceToken();
2835
2836 return true;
2837}
2838
John Kessenich5f934b02016-03-13 17:58:25 -06002839// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002840// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002841//
John Kessenich21472ae2016-06-04 11:46:33 -06002842bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002843{
John Kessenich21472ae2016-06-04 11:46:33 -06002844 TIntermAggregate* compoundStatement = nullptr;
2845
John Kessenich34fb0362016-05-03 23:17:20 -06002846 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002847 if (! acceptTokenClass(EHTokLeftBrace))
2848 return false;
2849
2850 // statement statement ...
2851 TIntermNode* statement = nullptr;
2852 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002853 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2854 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2855 branch->getFlowOp() == EOpDefault)) {
2856 // hook up individual subsequences within a switch statement
2857 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2858 compoundStatement = nullptr;
2859 } else {
2860 // hook it up to the growing compound statement
2861 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2862 }
John Kessenich5f934b02016-03-13 17:58:25 -06002863 }
John Kessenich34fb0362016-05-03 23:17:20 -06002864 if (compoundStatement)
2865 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002866
John Kessenich21472ae2016-06-04 11:46:33 -06002867 retStatement = compoundStatement;
2868
John Kessenich34fb0362016-05-03 23:17:20 -06002869 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002870 return acceptTokenClass(EHTokRightBrace);
2871}
2872
John Kessenich0d2b6de2016-06-05 11:23:11 -06002873bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2874{
2875 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002876 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002877 parseContext.popScope();
2878
2879 return result;
2880}
2881
John Kessenich077e0522016-06-09 02:02:17 -06002882bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002883{
John Kessenich077e0522016-06-09 02:02:17 -06002884 parseContext.pushScope();
2885 bool result = acceptCompoundStatement(statement);
2886 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002887
2888 return result;
2889}
2890
John Kessenich5f934b02016-03-13 17:58:25 -06002891// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002892// : attributes attributed_statement
2893//
2894// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002895// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002896// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002897// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002898// | declaration_statement
2899// | selection_statement
2900// | switch_statement
2901// | case_label
2902// | iteration_statement
2903// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002904//
2905bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2906{
John Kessenich21472ae2016-06-04 11:46:33 -06002907 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002908
John Kessenich21472ae2016-06-04 11:46:33 -06002909 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002910 TAttributeMap attributes;
2911 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002912
John Kessenich21472ae2016-06-04 11:46:33 -06002913 // attributed_statement
2914 switch (peek()) {
2915 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002916 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002917
John Kessenich21472ae2016-06-04 11:46:33 -06002918 case EHTokIf:
2919 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002920
John Kessenich21472ae2016-06-04 11:46:33 -06002921 case EHTokSwitch:
2922 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002923
John Kessenich21472ae2016-06-04 11:46:33 -06002924 case EHTokFor:
2925 case EHTokDo:
2926 case EHTokWhile:
2927 return acceptIterationStatement(statement);
2928
2929 case EHTokContinue:
2930 case EHTokBreak:
2931 case EHTokDiscard:
2932 case EHTokReturn:
2933 return acceptJumpStatement(statement);
2934
2935 case EHTokCase:
2936 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002937 case EHTokDefault:
2938 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002939
2940 case EHTokSemicolon:
2941 return acceptTokenClass(EHTokSemicolon);
2942
2943 case EHTokRightBrace:
2944 // Performance: not strictly necessary, but stops a bunch of hunting early,
2945 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002946 return false;
2947
John Kessenich21472ae2016-06-04 11:46:33 -06002948 default:
2949 {
2950 // declaration
2951 if (acceptDeclaration(statement))
2952 return true;
2953
2954 // expression
2955 TIntermTyped* node;
2956 if (acceptExpression(node))
2957 statement = node;
2958 else
2959 return false;
2960
2961 // SEMICOLON (following an expression)
2962 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002963 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002964 return false;
2965 }
2966 }
2967 }
2968
John Kessenich5f934b02016-03-13 17:58:25 -06002969 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002970}
2971
John Kessenich21472ae2016-06-04 11:46:33 -06002972// attributes
2973// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2974//
2975// attribute:
2976// : UNROLL
2977// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2978// | FASTOPT
2979// | ALLOW_UAV_CONDITION
2980// | BRANCH
2981// | FLATTEN
2982// | FORCECASE
2983// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06002984// | DOMAIN
2985// | EARLYDEPTHSTENCIL
2986// | INSTANCE
2987// | MAXTESSFACTOR
2988// | OUTPUTCONTROLPOINTS
2989// | OUTPUTTOPOLOGY
2990// | PARTITIONING
2991// | PATCHCONSTANTFUNC
2992// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06002993//
steve-lunarg1868b142016-10-20 13:07:10 -06002994void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06002995{
steve-lunarg1868b142016-10-20 13:07:10 -06002996 // For now, accept the [ XXX(X) ] syntax, but drop all but
2997 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06002998 // TODO: subset to correct set? Pass on?
2999 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003000 HlslToken idToken;
3001
John Kessenich0d2b6de2016-06-05 11:23:11 -06003002 // LEFT_BRACKET?
3003 if (! acceptTokenClass(EHTokLeftBracket))
3004 return;
3005
3006 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003007 if (acceptIdentifier(idToken)) {
3008 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003009 } else if (! peekTokenClass(EHTokRightBracket)) {
3010 expected("identifier");
3011 advanceToken();
3012 }
3013
steve-lunarga22f7db2016-11-11 08:17:44 -07003014 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003015
3016 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003017 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003018 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003019
John Kessenich0d2b6de2016-06-05 11:23:11 -06003020 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003021 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003022
steve-lunarga22f7db2016-11-11 08:17:44 -07003023 while (acceptAssignmentExpression(node)) {
3024 expectingExpression = false;
3025 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003026 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003027 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003028 }
3029
steve-lunarga22f7db2016-11-11 08:17:44 -07003030 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003031 if (! acceptTokenClass(EHTokRightParen))
3032 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003033
3034 // Error for partial or missing expression
3035 if (expectingExpression || expressions->getSequence().empty())
3036 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003037 }
3038
3039 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003040 if (!acceptTokenClass(EHTokRightBracket)) {
3041 expected("]");
3042 return;
3043 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003044
steve-lunarg1868b142016-10-20 13:07:10 -06003045 // Add any values we found into the attribute map. This accepts
3046 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003047 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003048 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003049}
3050
John Kessenich0d2b6de2016-06-05 11:23:11 -06003051// selection_statement
3052// : IF LEFT_PAREN expression RIGHT_PAREN statement
3053// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3054//
John Kessenich21472ae2016-06-04 11:46:33 -06003055bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3056{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003057 TSourceLoc loc = token.loc;
3058
3059 // IF
3060 if (! acceptTokenClass(EHTokIf))
3061 return false;
3062
3063 // so that something declared in the condition is scoped to the lifetimes
3064 // of the then-else statements
3065 parseContext.pushScope();
3066
3067 // LEFT_PAREN expression RIGHT_PAREN
3068 TIntermTyped* condition;
3069 if (! acceptParenExpression(condition))
3070 return false;
3071
3072 // create the child statements
3073 TIntermNodePair thenElse = { nullptr, nullptr };
3074
3075 // then statement
3076 if (! acceptScopedStatement(thenElse.node1)) {
3077 expected("then statement");
3078 return false;
3079 }
3080
3081 // ELSE
3082 if (acceptTokenClass(EHTokElse)) {
3083 // else statement
3084 if (! acceptScopedStatement(thenElse.node2)) {
3085 expected("else statement");
3086 return false;
3087 }
3088 }
3089
3090 // Put the pieces together
3091 statement = intermediate.addSelection(condition, thenElse, loc);
3092 parseContext.popScope();
3093
3094 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003095}
3096
John Kessenichd02dc5d2016-07-01 00:04:11 -06003097// switch_statement
3098// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3099//
John Kessenich21472ae2016-06-04 11:46:33 -06003100bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3101{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003102 // SWITCH
3103 TSourceLoc loc = token.loc;
3104 if (! acceptTokenClass(EHTokSwitch))
3105 return false;
3106
3107 // LEFT_PAREN expression RIGHT_PAREN
3108 parseContext.pushScope();
3109 TIntermTyped* switchExpression;
3110 if (! acceptParenExpression(switchExpression)) {
3111 parseContext.popScope();
3112 return false;
3113 }
3114
3115 // compound_statement
3116 parseContext.pushSwitchSequence(new TIntermSequence);
3117 bool statementOkay = acceptCompoundStatement(statement);
3118 if (statementOkay)
3119 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3120
3121 parseContext.popSwitchSequence();
3122 parseContext.popScope();
3123
3124 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003125}
3126
John Kessenich119f8f62016-06-05 15:44:07 -06003127// iteration_statement
3128// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3129// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3130// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3131//
3132// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003133bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3134{
John Kessenich119f8f62016-06-05 15:44:07 -06003135 TSourceLoc loc = token.loc;
3136 TIntermTyped* condition = nullptr;
3137
3138 EHlslTokenClass loop = peek();
3139 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3140
3141 // WHILE or DO or FOR
3142 advanceToken();
3143
3144 switch (loop) {
3145 case EHTokWhile:
3146 // so that something declared in the condition is scoped to the lifetime
3147 // of the while sub-statement
3148 parseContext.pushScope();
3149 parseContext.nestLooping();
3150
3151 // LEFT_PAREN condition RIGHT_PAREN
3152 if (! acceptParenExpression(condition))
3153 return false;
3154
3155 // statement
3156 if (! acceptScopedStatement(statement)) {
3157 expected("while sub-statement");
3158 return false;
3159 }
3160
3161 parseContext.unnestLooping();
3162 parseContext.popScope();
3163
3164 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3165
3166 return true;
3167
3168 case EHTokDo:
3169 parseContext.nestLooping();
3170
3171 if (! acceptTokenClass(EHTokLeftBrace))
3172 expected("{");
3173
3174 // statement
3175 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3176 expected("do sub-statement");
3177 return false;
3178 }
3179
3180 if (! acceptTokenClass(EHTokRightBrace))
3181 expected("}");
3182
3183 // WHILE
3184 if (! acceptTokenClass(EHTokWhile)) {
3185 expected("while");
3186 return false;
3187 }
3188
3189 // LEFT_PAREN condition RIGHT_PAREN
3190 TIntermTyped* condition;
3191 if (! acceptParenExpression(condition))
3192 return false;
3193
3194 if (! acceptTokenClass(EHTokSemicolon))
3195 expected(";");
3196
3197 parseContext.unnestLooping();
3198
3199 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3200
3201 return true;
3202
3203 case EHTokFor:
3204 {
3205 // LEFT_PAREN
3206 if (! acceptTokenClass(EHTokLeftParen))
3207 expected("(");
3208
3209 // so that something declared in the condition is scoped to the lifetime
3210 // of the for sub-statement
3211 parseContext.pushScope();
3212
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003213 // initializer
3214 TIntermNode* initNode = nullptr;
3215 if (! acceptControlDeclaration(initNode)) {
3216 TIntermTyped* initExpr = nullptr;
3217 acceptExpression(initExpr);
3218 initNode = initExpr;
3219 }
3220 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003221 if (! acceptTokenClass(EHTokSemicolon))
3222 expected(";");
3223
3224 parseContext.nestLooping();
3225
3226 // condition SEMI_COLON
3227 acceptExpression(condition);
3228 if (! acceptTokenClass(EHTokSemicolon))
3229 expected(";");
3230
3231 // iterator SEMI_COLON
3232 TIntermTyped* iterator = nullptr;
3233 acceptExpression(iterator);
3234 if (! acceptTokenClass(EHTokRightParen))
3235 expected(")");
3236
3237 // statement
3238 if (! acceptScopedStatement(statement)) {
3239 expected("for sub-statement");
3240 return false;
3241 }
3242
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003243 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003244
3245 parseContext.popScope();
3246 parseContext.unnestLooping();
3247
3248 return true;
3249 }
3250
3251 default:
3252 return false;
3253 }
John Kessenich21472ae2016-06-04 11:46:33 -06003254}
3255
3256// jump_statement
3257// : CONTINUE SEMICOLON
3258// | BREAK SEMICOLON
3259// | DISCARD SEMICOLON
3260// | RETURN SEMICOLON
3261// | RETURN expression SEMICOLON
3262//
3263bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3264{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003265 EHlslTokenClass jump = peek();
3266 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003267 case EHTokContinue:
3268 case EHTokBreak:
3269 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003270 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003271 advanceToken();
3272 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003273 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003274 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003275 return false;
3276 }
John Kessenich21472ae2016-06-04 11:46:33 -06003277
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003278 switch (jump) {
3279 case EHTokContinue:
3280 statement = intermediate.addBranch(EOpContinue, token.loc);
3281 break;
3282 case EHTokBreak:
3283 statement = intermediate.addBranch(EOpBreak, token.loc);
3284 break;
3285 case EHTokDiscard:
3286 statement = intermediate.addBranch(EOpKill, token.loc);
3287 break;
3288
3289 case EHTokReturn:
3290 {
3291 // expression
3292 TIntermTyped* node;
3293 if (acceptExpression(node)) {
3294 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003295 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003296 } else
3297 statement = intermediate.addBranch(EOpReturn, token.loc);
3298 break;
3299 }
3300
3301 default:
3302 assert(0);
3303 return false;
3304 }
3305
3306 // SEMICOLON
3307 if (! acceptTokenClass(EHTokSemicolon))
3308 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003309
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003310 return true;
3311}
John Kessenich21472ae2016-06-04 11:46:33 -06003312
John Kessenichd02dc5d2016-07-01 00:04:11 -06003313// case_label
3314// : CASE expression COLON
3315//
John Kessenich21472ae2016-06-04 11:46:33 -06003316bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3317{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003318 TSourceLoc loc = token.loc;
3319 if (! acceptTokenClass(EHTokCase))
3320 return false;
3321
3322 TIntermTyped* expression;
3323 if (! acceptExpression(expression)) {
3324 expected("case expression");
3325 return false;
3326 }
3327
3328 if (! acceptTokenClass(EHTokColon)) {
3329 expected(":");
3330 return false;
3331 }
3332
3333 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3334
3335 return true;
3336}
3337
3338// default_label
3339// : DEFAULT COLON
3340//
3341bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3342{
3343 TSourceLoc loc = token.loc;
3344 if (! acceptTokenClass(EHTokDefault))
3345 return false;
3346
3347 if (! acceptTokenClass(EHTokColon)) {
3348 expected(":");
3349 return false;
3350 }
3351
3352 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3353
3354 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003355}
3356
John Kessenich19b92ff2016-06-19 11:50:34 -06003357// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003358// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3359// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003360//
3361void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3362{
3363 arraySizes = nullptr;
3364
steve-lunarg7b211a32016-10-13 12:26:18 -06003365 // Early-out if there aren't any array dimensions
3366 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003367 return;
3368
steve-lunarg7b211a32016-10-13 12:26:18 -06003369 // 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 -06003370 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003371
3372 // Collect each array dimension.
3373 while (acceptTokenClass(EHTokLeftBracket)) {
3374 TSourceLoc loc = token.loc;
3375 TIntermTyped* sizeExpr = nullptr;
3376
John Kessenich057df292017-03-06 18:18:37 -07003377 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003378 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3379
3380 if (! acceptTokenClass(EHTokRightBracket)) {
3381 expected("]");
3382 return;
3383 }
3384
3385 if (hasArraySize) {
3386 TArraySize arraySize;
3387 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3388 arraySizes->addInnerSize(arraySize);
3389 } else {
3390 arraySizes->addInnerSize(0); // sized by initializers.
3391 }
steve-lunarg265c0612016-09-27 10:57:35 -06003392 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003393}
3394
John Kessenich630dd7d2016-06-12 23:52:12 -06003395// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003396// : COLON semantic // optional
3397// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3398// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003399// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003400// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003401//
John Kessenich854fe242017-03-02 14:30:59 -07003402// Return true if any tokens were accepted. That is,
3403// false can be returned on successfully recognizing nothing,
3404// not necessarily meaning bad syntax.
3405//
3406bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003407{
John Kessenich854fe242017-03-02 14:30:59 -07003408 bool found = false;
3409
John Kessenich630dd7d2016-06-12 23:52:12 -06003410 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003411 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003412 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003413 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003414 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003415 if (peekTokenClass(EHTokLayout))
3416 acceptLayoutQualifierList(qualifier);
3417 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003418 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003419 if (! acceptTokenClass(EHTokLeftParen)) {
3420 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003421 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003422 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003423 HlslToken locationToken;
3424 if (! acceptIdentifier(locationToken)) {
3425 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003426 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003427 }
3428 HlslToken componentToken;
3429 if (acceptTokenClass(EHTokDot)) {
3430 if (! acceptIdentifier(componentToken)) {
3431 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003432 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003433 }
3434 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003435 if (! acceptTokenClass(EHTokRightParen)) {
3436 expected(")");
3437 break;
3438 }
John Kessenich7735b942016-09-05 12:40:06 -06003439 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003440 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003441 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003442 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003443 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003444 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3445 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003446 if (! acceptTokenClass(EHTokLeftParen)) {
3447 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003448 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003449 }
John Kessenichb38f0712016-07-30 10:29:54 -06003450 HlslToken registerDesc; // for Type#
3451 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003452 if (! acceptIdentifier(registerDesc)) {
3453 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003454 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003455 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003456 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3457 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003458 // Then we didn't really see the registerDesc yet, it was
3459 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003460 profile = registerDesc;
3461 if (! acceptIdentifier(registerDesc)) {
3462 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003463 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003464 }
3465 }
John Kessenichb38f0712016-07-30 10:29:54 -06003466 int subComponent = 0;
3467 if (acceptTokenClass(EHTokLeftBracket)) {
3468 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3469 if (! peekTokenClass(EHTokIntConstant)) {
3470 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003471 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003472 }
3473 subComponent = token.i;
3474 advanceToken();
3475 if (! acceptTokenClass(EHTokRightBracket)) {
3476 expected("]");
3477 break;
3478 }
3479 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003480 // (COMMA SPACEN)opt
3481 HlslToken spaceDesc;
3482 if (acceptTokenClass(EHTokComma)) {
3483 if (! acceptIdentifier(spaceDesc)) {
3484 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003485 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003486 }
3487 }
3488 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003489 if (! acceptTokenClass(EHTokRightParen)) {
3490 expected(")");
3491 break;
3492 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003493 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003494 } else {
3495 // semantic, in idToken.string
John Kessenich6e1d50a2017-03-09 14:37:32 -07003496 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(*idToken.string));
John Kessenich630dd7d2016-06-12 23:52:12 -06003497 }
John Kessenich854fe242017-03-02 14:30:59 -07003498 } else if (peekTokenClass(EHTokLeftAngle)) {
3499 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003500 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003501 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003502 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003503
John Kessenich630dd7d2016-06-12 23:52:12 -06003504 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003505
3506 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003507}
3508
John Kesseniche01a9bc2016-03-12 20:11:22 -07003509} // end namespace glslang