blob: 39de92e70e2eed438fcb68feee5fa094ee9d00d1 [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
John Kessenich088d52b2017-03-11 17:55:28 -0700304 TFunctionDeclarator declarator;
305 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600306
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
John Kessenich088d52b2017-03-11 17:55:28 -0700337 declarator.function = new TFunction(fnName, declaredType);
338 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700339 expected("function parameter list");
340 return false;
341 }
342
John Kessenich630dd7d2016-06-12 23:52:12 -0600343 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700344 acceptPostDecls(declarator.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?
John Kessenich088d52b2017-03-11 17:55:28 -0700347 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600348 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700349 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600350 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600351 if (typedefDecl)
352 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700353 return acceptFunctionDefinition(declarator, nodeList);
John Kessenich5e69ec62016-07-05 00:02:40 -0600354 } else {
355 if (typedefDecl)
356 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700357 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600358 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600359 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600360 // A variable declaration. Fix the storage qualifier if it's a global.
361 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
362 declaredType.getQualifier().storage = EvqUniform;
363
John Kessenichecba76f2017-01-06 00:34:48 -0700364 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600365 // the number of types can expand when arrayness is different.
366 TType variableType;
367 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600368
John Kesseniche82061d2016-09-27 14:38:57 -0600369 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600370 TArraySizes* arraySizes = nullptr;
371 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600372
John Kesseniche82061d2016-09-27 14:38:57 -0600373 // Fix arrayness in the variableType
374 if (declaredType.isImplicitlySizedArray()) {
375 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
376 // of different sizes, for this case sharing the shallow copy of arrayness
377 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
378 variableType.newArraySizes(declaredType.getArraySizes());
379 }
380 if (arraySizes || variableType.isArray()) {
381 // In the most general case, arrayness is potentially coming both from the
382 // declared type and from the variable: "int[] a[];" or just one or the other.
383 // Merge it all to the variableType, so all arrayness is part of the variableType.
384 parseContext.arrayDimMerge(variableType, arraySizes);
385 }
386
LoopDawg4886f692016-06-29 10:58:58 -0600387 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600388 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600389 if (! acceptSamplerState())
390 return false;
391 }
392
John Kessenichd5ed0b62016-07-04 17:32:45 -0600393 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600394 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600395
396 // EQUAL assignment_expression
397 TIntermTyped* expressionNode = nullptr;
398 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600399 if (typedefDecl)
400 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600401 if (! acceptAssignmentExpression(expressionNode)) {
402 expected("initializer");
403 return false;
404 }
405 }
406
John Kessenich6dbc0a72016-09-27 19:13:05 -0600407 // TODO: things scoped within an annotation need their own name space;
408 // TODO: strings are not yet handled.
409 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
410 if (typedefDecl)
411 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
412 else if (variableType.getBasicType() == EbtBlock)
steve-lunargdd8287a2017-02-23 18:04:12 -0700413 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600414 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700415 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600416 // this isn't really an individual variable, but a member of the $Global buffer
417 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
418 } else {
419 // Declare the variable and add any initializer code to the AST.
420 // The top-level node is always made into an aggregate, as that's
421 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700422 initializers = intermediate.growAggregate(initializers,
423 parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
424 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600425 }
426 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600427 }
John Kessenich5f934b02016-03-13 17:58:25 -0600428 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600429
430 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700431 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600432 continue;
433 }
434 };
435
John Kessenichca71d942017-03-07 20:44:09 -0700436 // The top-level initializer node is a sequence.
437 if (initializers != nullptr)
438 initializers->setOperator(EOpSequence);
439
440 // Add the initializers' aggregate to the nodeList we were handed.
441 if (nodeList)
442 nodeList = intermediate.growAggregate(nodeList, initializers);
443 else
444 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700445
John Kessenich078d7f22016-03-14 10:02:11 -0600446 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600447 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700448 // This may have been a false detection of what appeared to be a declaration, but
449 // was actually an assignment such as "float = 4", where "float" is an identifier.
450 // We put the token back to let further parsing happen for cases where that may
451 // happen. This errors on the side of caution, and mostly triggers the error.
452
453 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
454 recedeToken();
455 else
456 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600457 return false;
458 }
John Kessenichecba76f2017-01-06 00:34:48 -0700459
John Kesseniche01a9bc2016-03-12 20:11:22 -0700460 return true;
461}
462
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600463// control_declaration
464// : fully_specified_type identifier EQUAL expression
465//
466bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
467{
468 node = nullptr;
469
470 // fully_specified_type
471 TType type;
472 if (! acceptFullySpecifiedType(type))
473 return false;
474
John Kessenich057df292017-03-06 18:18:37 -0700475 // filter out type casts
476 if (peekTokenClass(EHTokLeftParen)) {
477 recedeToken();
478 return false;
479 }
480
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600481 // identifier
482 HlslToken idToken;
483 if (! acceptIdentifier(idToken)) {
484 expected("identifier");
485 return false;
486 }
487
488 // EQUAL
489 TIntermTyped* expressionNode = nullptr;
490 if (! acceptTokenClass(EHTokAssign)) {
491 expected("=");
492 return false;
493 }
494
495 // expression
496 if (! acceptExpression(expressionNode)) {
497 expected("initializer");
498 return false;
499 }
500
John Kesseniche82061d2016-09-27 14:38:57 -0600501 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600502
503 return true;
504}
505
John Kessenich87142c72016-03-12 20:24:24 -0700506// fully_specified_type
507// : type_specifier
508// | type_qualifier type_specifier
509//
510bool HlslGrammar::acceptFullySpecifiedType(TType& type)
511{
John Kessenich54ee28f2017-03-11 14:13:00 -0700512 TIntermNode* nodeList = nullptr;
513 return acceptFullySpecifiedType(type, nodeList);
514}
515bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
516{
John Kessenich87142c72016-03-12 20:24:24 -0700517 // type_qualifier
518 TQualifier qualifier;
519 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600520 if (! acceptQualifier(qualifier))
521 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600522 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700523
524 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700525 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700526 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700527 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700528 // qualifier. Back it out, if we did.
529 if (qualifier.sample)
530 recedeToken();
531
John Kessenich87142c72016-03-12 20:24:24 -0700532 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700533 }
John Kessenich3d157c52016-07-25 16:05:33 -0600534 if (type.getBasicType() == EbtBlock) {
535 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600536 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600537 // further, it can create an anonymous instance of the block
538 if (peekTokenClass(EHTokSemicolon))
539 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600540 } else {
541 // Some qualifiers are set when parsing the type. Merge those with
542 // whatever comes from acceptQualifier.
543 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700544
steve-lunargbb0183f2016-10-04 16:58:14 -0600545 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600546 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700547
steve-lunarg5da1f032017-02-12 17:50:28 -0700548 if (type.getQualifier().storage == EvqVaryingOut ||
549 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700550 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700551 qualifier.readonly = type.getQualifier().readonly;
552 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700553
554 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600555 }
John Kessenich87142c72016-03-12 20:24:24 -0700556
557 return true;
558}
559
John Kessenich630dd7d2016-06-12 23:52:12 -0600560// type_qualifier
561// : qualifier qualifier ...
562//
563// Zero or more of these, so this can't return false.
564//
John Kessenichb9e39122016-08-17 10:22:08 -0600565bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700566{
John Kessenich630dd7d2016-06-12 23:52:12 -0600567 do {
568 switch (peek()) {
569 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600570 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600571 break;
572 case EHTokExtern:
573 // TODO: no meaning in glslang?
574 break;
575 case EHTokShared:
576 // TODO: hint
577 break;
578 case EHTokGroupShared:
579 qualifier.storage = EvqShared;
580 break;
581 case EHTokUniform:
582 qualifier.storage = EvqUniform;
583 break;
584 case EHTokConst:
585 qualifier.storage = EvqConst;
586 break;
587 case EHTokVolatile:
588 qualifier.volatil = true;
589 break;
590 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600591 qualifier.smooth = true;
592 break;
593 case EHTokCentroid:
594 qualifier.centroid = true;
595 break;
596 case EHTokNointerpolation:
597 qualifier.flat = true;
598 break;
599 case EHTokNoperspective:
600 qualifier.nopersp = true;
601 break;
602 case EHTokSample:
603 qualifier.sample = true;
604 break;
605 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600606 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600607 break;
608 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600609 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600610 break;
611 case EHTokPrecise:
612 qualifier.noContraction = true;
613 break;
LoopDawg9249c702016-07-12 20:44:32 -0600614 case EHTokIn:
615 qualifier.storage = EvqIn;
616 break;
617 case EHTokOut:
618 qualifier.storage = EvqOut;
619 break;
620 case EHTokInOut:
621 qualifier.storage = EvqInOut;
622 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600623 case EHTokLayout:
624 if (! acceptLayoutQualifierList(qualifier))
625 return false;
626 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700627 case EHTokGloballyCoherent:
628 qualifier.coherent = true;
629 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700630
631 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
632 // for output variables.
633 case EHTokPoint:
634 qualifier.storage = EvqIn;
635 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
636 return false;
637 break;
638 case EHTokLine:
639 qualifier.storage = EvqIn;
640 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
641 return false;
642 break;
643 case EHTokTriangle:
644 qualifier.storage = EvqIn;
645 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
646 return false;
647 break;
648 case EHTokLineAdj:
649 qualifier.storage = EvqIn;
650 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
651 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700652 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700653 case EHTokTriangleAdj:
654 qualifier.storage = EvqIn;
655 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
656 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700657 break;
658
John Kessenich630dd7d2016-06-12 23:52:12 -0600659 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600660 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600661 }
662 advanceToken();
663 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700664}
665
John Kessenichb9e39122016-08-17 10:22:08 -0600666// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600667// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600668//
669// layout_qualifier
670// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600671// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600672//
673// Zero or more of these, so this can't return false.
674//
675bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
676{
677 if (! acceptTokenClass(EHTokLayout))
678 return false;
679
680 // LEFT_PAREN
681 if (! acceptTokenClass(EHTokLeftParen))
682 return false;
683
684 do {
685 // identifier
686 HlslToken idToken;
687 if (! acceptIdentifier(idToken))
688 break;
689
690 // EQUAL expression
691 if (acceptTokenClass(EHTokAssign)) {
692 TIntermTyped* expr;
693 if (! acceptConditionalExpression(expr)) {
694 expected("expression");
695 return false;
696 }
697 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
698 } else
699 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
700
701 // COMMA
702 if (! acceptTokenClass(EHTokComma))
703 break;
704 } while (true);
705
706 // RIGHT_PAREN
707 if (! acceptTokenClass(EHTokRightParen)) {
708 expected(")");
709 return false;
710 }
711
712 return true;
713}
714
LoopDawg6daaa4f2016-06-23 19:13:48 -0600715// template_type
716// : FLOAT
717// | DOUBLE
718// | INT
719// | DWORD
720// | UINT
721// | BOOL
722//
steve-lunargf49cdf42016-11-17 15:04:20 -0700723bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600724{
725 switch (peek()) {
726 case EHTokFloat:
727 basicType = EbtFloat;
728 break;
729 case EHTokDouble:
730 basicType = EbtDouble;
731 break;
732 case EHTokInt:
733 case EHTokDword:
734 basicType = EbtInt;
735 break;
736 case EHTokUint:
737 basicType = EbtUint;
738 break;
739 case EHTokBool:
740 basicType = EbtBool;
741 break;
742 default:
743 return false;
744 }
745
746 advanceToken();
747
748 return true;
749}
750
751// vector_template_type
752// : VECTOR
753// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
754//
755bool HlslGrammar::acceptVectorTemplateType(TType& type)
756{
757 if (! acceptTokenClass(EHTokVector))
758 return false;
759
760 if (! acceptTokenClass(EHTokLeftAngle)) {
761 // in HLSL, 'vector' alone means float4.
762 new(&type) TType(EbtFloat, EvqTemporary, 4);
763 return true;
764 }
765
766 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700767 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600768 expected("scalar type");
769 return false;
770 }
771
772 // COMMA
773 if (! acceptTokenClass(EHTokComma)) {
774 expected(",");
775 return false;
776 }
777
778 // integer
779 if (! peekTokenClass(EHTokIntConstant)) {
780 expected("literal integer");
781 return false;
782 }
783
784 TIntermTyped* vecSize;
785 if (! acceptLiteral(vecSize))
786 return false;
787
788 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
789
790 new(&type) TType(basicType, EvqTemporary, vecSizeI);
791
792 if (vecSizeI == 1)
793 type.makeVector();
794
795 if (!acceptTokenClass(EHTokRightAngle)) {
796 expected("right angle bracket");
797 return false;
798 }
799
800 return true;
801}
802
803// matrix_template_type
804// : MATRIX
805// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
806//
807bool HlslGrammar::acceptMatrixTemplateType(TType& type)
808{
809 if (! acceptTokenClass(EHTokMatrix))
810 return false;
811
812 if (! acceptTokenClass(EHTokLeftAngle)) {
813 // in HLSL, 'matrix' alone means float4x4.
814 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
815 return true;
816 }
817
818 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700819 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600820 expected("scalar type");
821 return false;
822 }
823
824 // COMMA
825 if (! acceptTokenClass(EHTokComma)) {
826 expected(",");
827 return false;
828 }
829
830 // integer rows
831 if (! peekTokenClass(EHTokIntConstant)) {
832 expected("literal integer");
833 return false;
834 }
835
836 TIntermTyped* rows;
837 if (! acceptLiteral(rows))
838 return false;
839
840 // COMMA
841 if (! acceptTokenClass(EHTokComma)) {
842 expected(",");
843 return false;
844 }
John Kessenichecba76f2017-01-06 00:34:48 -0700845
LoopDawg6daaa4f2016-06-23 19:13:48 -0600846 // integer cols
847 if (! peekTokenClass(EHTokIntConstant)) {
848 expected("literal integer");
849 return false;
850 }
851
852 TIntermTyped* cols;
853 if (! acceptLiteral(cols))
854 return false;
855
856 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600857 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
858 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600859
860 if (!acceptTokenClass(EHTokRightAngle)) {
861 expected("right angle bracket");
862 return false;
863 }
864
865 return true;
866}
867
steve-lunargf49cdf42016-11-17 15:04:20 -0700868// layout_geometry
869// : LINESTREAM
870// | POINTSTREAM
871// | TRIANGLESTREAM
872//
873bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
874{
875 // read geometry type
876 const EHlslTokenClass geometryType = peek();
877
878 switch (geometryType) {
879 case EHTokPointStream: geometry = ElgPoints; break;
880 case EHTokLineStream: geometry = ElgLineStrip; break;
881 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
882 default:
883 return false; // not a layout geometry
884 }
885
886 advanceToken(); // consume the layout keyword
887 return true;
888}
889
steve-lunarg858c9282017-01-07 08:54:10 -0700890// tessellation_decl_type
891// : INPUTPATCH
892// | OUTPUTPATCH
893//
894bool HlslGrammar::acceptTessellationDeclType()
895{
896 // read geometry type
897 const EHlslTokenClass tessType = peek();
898
899 switch (tessType) {
900 case EHTokInputPatch: break;
901 case EHTokOutputPatch: break;
902 default:
903 return false; // not a tessellation decl
904 }
905
906 advanceToken(); // consume the keyword
907 return true;
908}
909
910// tessellation_patch_template_type
911// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
912//
913bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
914{
915 if (! acceptTessellationDeclType())
916 return false;
917
918 if (! acceptTokenClass(EHTokLeftAngle))
919 return false;
920
921 if (! acceptType(type)) {
922 expected("tessellation patch type");
923 return false;
924 }
925
926 if (! acceptTokenClass(EHTokComma))
927 return false;
928
929 // integer size
930 if (! peekTokenClass(EHTokIntConstant)) {
931 expected("literal integer");
932 return false;
933 }
934
935 TIntermTyped* size;
936 if (! acceptLiteral(size))
937 return false;
938
939 TArraySizes* arraySizes = new TArraySizes;
940 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
941 type.newArraySizes(*arraySizes);
942
943 if (! acceptTokenClass(EHTokRightAngle)) {
944 expected("right angle bracket");
945 return false;
946 }
947
948 return true;
949}
950
steve-lunargf49cdf42016-11-17 15:04:20 -0700951// stream_out_template_type
952// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
953//
954bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
955{
956 geometry = ElgNone;
957
958 if (! acceptOutputPrimitiveGeometry(geometry))
959 return false;
960
961 if (! acceptTokenClass(EHTokLeftAngle))
962 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700963
steve-lunargf49cdf42016-11-17 15:04:20 -0700964 if (! acceptType(type)) {
965 expected("stream output type");
966 return false;
967 }
968
969 type.getQualifier().storage = EvqVaryingOut;
970
971 if (! acceptTokenClass(EHTokRightAngle)) {
972 expected("right angle bracket");
973 return false;
974 }
975
976 return true;
977}
John Kessenichecba76f2017-01-06 00:34:48 -0700978
John Kessenicha1e2d492016-09-20 13:22:58 -0600979// annotations
980// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600981//
John Kessenicha1e2d492016-09-20 13:22:58 -0600982bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600983{
John Kessenicha1e2d492016-09-20 13:22:58 -0600984 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600985 return false;
986
John Kessenicha1e2d492016-09-20 13:22:58 -0600987 // note that we are nesting a name space
988 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600989
990 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
991 do {
992 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
993 while (acceptTokenClass(EHTokSemicolon))
994 ;
995
996 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -0600997 break;
John Kessenich86f71382016-09-19 20:23:18 -0600998
999 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001000 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001001 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001002 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001003 return false;
1004 }
1005 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001006
1007 parseContext.unnestAnnotations();
1008 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001009}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001010
LoopDawg4886f692016-06-29 10:58:58 -06001011// sampler_type
1012// : SAMPLER
1013// | SAMPLER1D
1014// | SAMPLER2D
1015// | SAMPLER3D
1016// | SAMPLERCUBE
1017// | SAMPLERSTATE
1018// | SAMPLERCOMPARISONSTATE
1019bool HlslGrammar::acceptSamplerType(TType& type)
1020{
1021 // read sampler type
1022 const EHlslTokenClass samplerType = peek();
1023
LoopDawga78b0292016-07-19 14:28:05 -06001024 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001025 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001026
LoopDawga78b0292016-07-19 14:28:05 -06001027 bool isShadow = false;
1028
LoopDawg4886f692016-06-29 10:58:58 -06001029 switch (samplerType) {
1030 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001031 case EHTokSampler1d: /*dim = Esd1D*/; break;
1032 case EHTokSampler2d: /*dim = Esd2D*/; break;
1033 case EHTokSampler3d: /*dim = Esd3D*/; break;
1034 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001035 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001036 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001037 default:
1038 return false; // not a sampler declaration
1039 }
1040
1041 advanceToken(); // consume the sampler type keyword
1042
1043 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001044
1045 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001046 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001047
1048 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1049
1050 return true;
1051}
1052
1053// texture_type
1054// | BUFFER
1055// | TEXTURE1D
1056// | TEXTURE1DARRAY
1057// | TEXTURE2D
1058// | TEXTURE2DARRAY
1059// | TEXTURE3D
1060// | TEXTURECUBE
1061// | TEXTURECUBEARRAY
1062// | TEXTURE2DMS
1063// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001064// | RWBUFFER
1065// | RWTEXTURE1D
1066// | RWTEXTURE1DARRAY
1067// | RWTEXTURE2D
1068// | RWTEXTURE2DARRAY
1069// | RWTEXTURE3D
1070
LoopDawg4886f692016-06-29 10:58:58 -06001071bool HlslGrammar::acceptTextureType(TType& type)
1072{
1073 const EHlslTokenClass textureType = peek();
1074
1075 TSamplerDim dim = EsdNone;
1076 bool array = false;
1077 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001078 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -06001079
1080 switch (textureType) {
1081 case EHTokBuffer: dim = EsdBuffer; break;
1082 case EHTokTexture1d: dim = Esd1D; break;
1083 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1084 case EHTokTexture2d: dim = Esd2D; break;
1085 case EHTokTexture2darray: dim = Esd2D; array = true; break;
John Kessenichecba76f2017-01-06 00:34:48 -07001086 case EHTokTexture3d: dim = Esd3D; break;
LoopDawg4886f692016-06-29 10:58:58 -06001087 case EHTokTextureCube: dim = EsdCube; break;
1088 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1089 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1090 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001091 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1092 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1093 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1094 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1095 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1096 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001097 default:
1098 return false; // not a texture declaration
1099 }
1100
1101 advanceToken(); // consume the texture object keyword
1102
1103 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001104
LoopDawg4886f692016-06-29 10:58:58 -06001105 TIntermTyped* msCount = nullptr;
1106
steve-lunargbb0183f2016-10-04 16:58:14 -06001107 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001108 if (acceptTokenClass(EHTokLeftAngle)) {
1109 if (! acceptType(txType)) {
1110 expected("scalar or vector type");
1111 return false;
1112 }
1113
1114 const TBasicType basicRetType = txType.getBasicType() ;
1115
1116 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1117 unimplemented("basic type in texture");
1118 return false;
1119 }
1120
steve-lunargd53f7172016-07-27 15:46:48 -06001121 // Buffers can handle small mats if they fit in 4 components
1122 if (dim == EsdBuffer && txType.isMatrix()) {
1123 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1124 expected("components < 4 in matrix buffer type");
1125 return false;
1126 }
1127
1128 // TODO: except we don't handle it yet...
1129 unimplemented("matrix type in buffer");
1130 return false;
1131 }
1132
LoopDawg4886f692016-06-29 10:58:58 -06001133 if (!txType.isScalar() && !txType.isVector()) {
1134 expected("scalar or vector type");
1135 return false;
1136 }
1137
LoopDawg4886f692016-06-29 10:58:58 -06001138 if (ms && acceptTokenClass(EHTokComma)) {
1139 // read sample count for multisample types, if given
1140 if (! peekTokenClass(EHTokIntConstant)) {
1141 expected("multisample count");
1142 return false;
1143 }
1144
1145 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1146 return false;
1147 }
1148
1149 if (! acceptTokenClass(EHTokRightAngle)) {
1150 expected("right angle bracket");
1151 return false;
1152 }
1153 } else if (ms) {
1154 expected("texture type for multisample");
1155 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001156 } else if (image) {
1157 expected("type for RWTexture/RWBuffer");
1158 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001159 }
1160
1161 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001162 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001163
1164 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001165 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001166
steve-lunarg4f2da272016-10-10 15:24:57 -06001167 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1168 if (image || dim == EsdBuffer)
1169 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001170
1171 // Non-image Buffers are combined
1172 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001173 sampler.set(txType.getBasicType(), dim, array);
1174 } else {
1175 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001176 if (image) {
1177 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1178 } else {
1179 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1180 }
steve-lunargd53f7172016-07-27 15:46:48 -06001181 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001182
1183 // Remember the declared vector size.
1184 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001185
LoopDawg4886f692016-06-29 10:58:58 -06001186 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001187 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001188
1189 return true;
1190}
1191
John Kessenich87142c72016-03-12 20:24:24 -07001192// If token is for a type, update 'type' with the type information,
1193// and return true and advance.
1194// Otherwise, return false, and don't advance
1195bool HlslGrammar::acceptType(TType& type)
1196{
John Kessenich54ee28f2017-03-11 14:13:00 -07001197 TIntermNode* nodeList = nullptr;
1198 return acceptType(type, nodeList);
1199}
1200bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1201{
steve-lunarg3226b082016-10-26 19:18:55 -06001202 // Basic types for min* types, broken out here in case of future
1203 // changes, e.g, to use native halfs.
1204 static const TBasicType min16float_bt = EbtFloat;
1205 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001206 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001207 static const TBasicType min16int_bt = EbtInt;
1208 static const TBasicType min12int_bt = EbtInt;
1209 static const TBasicType min16uint_bt = EbtUint;
1210
John Kessenich9c86c6a2016-05-03 22:49:24 -06001211 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001212 case EHTokVector:
1213 return acceptVectorTemplateType(type);
1214 break;
1215
1216 case EHTokMatrix:
1217 return acceptMatrixTemplateType(type);
1218 break;
1219
steve-lunargf49cdf42016-11-17 15:04:20 -07001220 case EHTokPointStream: // fall through
1221 case EHTokLineStream: // ...
1222 case EHTokTriangleStream: // ...
1223 {
1224 TLayoutGeometry geometry;
1225 if (! acceptStreamOutTemplateType(type, geometry))
1226 return false;
1227
1228 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1229 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001230
steve-lunargf49cdf42016-11-17 15:04:20 -07001231 return true;
1232 }
1233
steve-lunarg858c9282017-01-07 08:54:10 -07001234 case EHTokInputPatch: // fall through
1235 case EHTokOutputPatch: // ...
1236 {
1237 if (! acceptTessellationPatchTemplateType(type))
1238 return false;
1239
1240 return true;
1241 }
1242
LoopDawg4886f692016-06-29 10:58:58 -06001243 case EHTokSampler: // fall through
1244 case EHTokSampler1d: // ...
1245 case EHTokSampler2d: // ...
1246 case EHTokSampler3d: // ...
1247 case EHTokSamplerCube: // ...
1248 case EHTokSamplerState: // ...
1249 case EHTokSamplerComparisonState: // ...
1250 return acceptSamplerType(type);
1251 break;
1252
1253 case EHTokBuffer: // fall through
1254 case EHTokTexture1d: // ...
1255 case EHTokTexture1darray: // ...
1256 case EHTokTexture2d: // ...
1257 case EHTokTexture2darray: // ...
1258 case EHTokTexture3d: // ...
1259 case EHTokTextureCube: // ...
1260 case EHTokTextureCubearray: // ...
1261 case EHTokTexture2DMS: // ...
1262 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001263 case EHTokRWTexture1d: // ...
1264 case EHTokRWTexture1darray: // ...
1265 case EHTokRWTexture2d: // ...
1266 case EHTokRWTexture2darray: // ...
1267 case EHTokRWTexture3d: // ...
1268 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001269 return acceptTextureType(type);
1270 break;
1271
steve-lunarg5da1f032017-02-12 17:50:28 -07001272 case EHTokAppendStructuredBuffer:
1273 case EHTokByteAddressBuffer:
1274 case EHTokConsumeStructuredBuffer:
1275 case EHTokRWByteAddressBuffer:
1276 case EHTokRWStructuredBuffer:
1277 case EHTokStructuredBuffer:
1278 return acceptStructBufferType(type);
1279 break;
1280
John Kessenich27ffb292017-03-03 17:01:01 -07001281 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001282 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001283 case EHTokCBuffer:
1284 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001285 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001286
1287 case EHTokIdentifier:
1288 // An identifier could be for a user-defined type.
1289 // Note we cache the symbol table lookup, to save for a later rule
1290 // when this is not a type.
John Kessenich854fe242017-03-02 14:30:59 -07001291 token.symbol = parseContext.lookupUserType(*token.string, type);
1292 if (token.symbol != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001293 advanceToken();
1294 return true;
1295 } else
1296 return false;
1297
John Kessenich71351de2016-06-08 12:50:56 -06001298 case EHTokVoid:
1299 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001300 break;
John Kessenich71351de2016-06-08 12:50:56 -06001301
John Kessenicha1e2d492016-09-20 13:22:58 -06001302 case EHTokString:
1303 new(&type) TType(EbtString);
1304 break;
1305
John Kessenich87142c72016-03-12 20:24:24 -07001306 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001307 new(&type) TType(EbtFloat);
1308 break;
John Kessenich87142c72016-03-12 20:24:24 -07001309 case EHTokFloat1:
1310 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001311 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001312 break;
John Kessenich87142c72016-03-12 20:24:24 -07001313 case EHTokFloat2:
1314 new(&type) TType(EbtFloat, EvqTemporary, 2);
1315 break;
1316 case EHTokFloat3:
1317 new(&type) TType(EbtFloat, EvqTemporary, 3);
1318 break;
1319 case EHTokFloat4:
1320 new(&type) TType(EbtFloat, EvqTemporary, 4);
1321 break;
1322
John Kessenich71351de2016-06-08 12:50:56 -06001323 case EHTokDouble:
1324 new(&type) TType(EbtDouble);
1325 break;
1326 case EHTokDouble1:
1327 new(&type) TType(EbtDouble);
1328 type.makeVector();
1329 break;
1330 case EHTokDouble2:
1331 new(&type) TType(EbtDouble, EvqTemporary, 2);
1332 break;
1333 case EHTokDouble3:
1334 new(&type) TType(EbtDouble, EvqTemporary, 3);
1335 break;
1336 case EHTokDouble4:
1337 new(&type) TType(EbtDouble, EvqTemporary, 4);
1338 break;
1339
1340 case EHTokInt:
1341 case EHTokDword:
1342 new(&type) TType(EbtInt);
1343 break;
1344 case EHTokInt1:
1345 new(&type) TType(EbtInt);
1346 type.makeVector();
1347 break;
John Kessenich87142c72016-03-12 20:24:24 -07001348 case EHTokInt2:
1349 new(&type) TType(EbtInt, EvqTemporary, 2);
1350 break;
1351 case EHTokInt3:
1352 new(&type) TType(EbtInt, EvqTemporary, 3);
1353 break;
1354 case EHTokInt4:
1355 new(&type) TType(EbtInt, EvqTemporary, 4);
1356 break;
1357
John Kessenich71351de2016-06-08 12:50:56 -06001358 case EHTokUint:
1359 new(&type) TType(EbtUint);
1360 break;
1361 case EHTokUint1:
1362 new(&type) TType(EbtUint);
1363 type.makeVector();
1364 break;
1365 case EHTokUint2:
1366 new(&type) TType(EbtUint, EvqTemporary, 2);
1367 break;
1368 case EHTokUint3:
1369 new(&type) TType(EbtUint, EvqTemporary, 3);
1370 break;
1371 case EHTokUint4:
1372 new(&type) TType(EbtUint, EvqTemporary, 4);
1373 break;
1374
1375 case EHTokBool:
1376 new(&type) TType(EbtBool);
1377 break;
1378 case EHTokBool1:
1379 new(&type) TType(EbtBool);
1380 type.makeVector();
1381 break;
John Kessenich87142c72016-03-12 20:24:24 -07001382 case EHTokBool2:
1383 new(&type) TType(EbtBool, EvqTemporary, 2);
1384 break;
1385 case EHTokBool3:
1386 new(&type) TType(EbtBool, EvqTemporary, 3);
1387 break;
1388 case EHTokBool4:
1389 new(&type) TType(EbtBool, EvqTemporary, 4);
1390 break;
1391
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001392 case EHTokHalf:
1393 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1394 break;
1395 case EHTokHalf1:
1396 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1397 type.makeVector();
1398 break;
1399 case EHTokHalf2:
1400 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1401 break;
1402 case EHTokHalf3:
1403 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1404 break;
1405 case EHTokHalf4:
1406 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1407 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001408
steve-lunarg3226b082016-10-26 19:18:55 -06001409 case EHTokMin16float:
1410 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1411 break;
1412 case EHTokMin16float1:
1413 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1414 type.makeVector();
1415 break;
1416 case EHTokMin16float2:
1417 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1418 break;
1419 case EHTokMin16float3:
1420 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1421 break;
1422 case EHTokMin16float4:
1423 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1424 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001425
steve-lunarg3226b082016-10-26 19:18:55 -06001426 case EHTokMin10float:
1427 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1428 break;
1429 case EHTokMin10float1:
1430 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1431 type.makeVector();
1432 break;
1433 case EHTokMin10float2:
1434 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1435 break;
1436 case EHTokMin10float3:
1437 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1438 break;
1439 case EHTokMin10float4:
1440 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1441 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001442
steve-lunarg3226b082016-10-26 19:18:55 -06001443 case EHTokMin16int:
1444 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1445 break;
1446 case EHTokMin16int1:
1447 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1448 type.makeVector();
1449 break;
1450 case EHTokMin16int2:
1451 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1452 break;
1453 case EHTokMin16int3:
1454 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1455 break;
1456 case EHTokMin16int4:
1457 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1458 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001459
steve-lunarg3226b082016-10-26 19:18:55 -06001460 case EHTokMin12int:
1461 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1462 break;
1463 case EHTokMin12int1:
1464 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1465 type.makeVector();
1466 break;
1467 case EHTokMin12int2:
1468 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1469 break;
1470 case EHTokMin12int3:
1471 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1472 break;
1473 case EHTokMin12int4:
1474 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1475 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001476
steve-lunarg3226b082016-10-26 19:18:55 -06001477 case EHTokMin16uint:
1478 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1479 break;
1480 case EHTokMin16uint1:
1481 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1482 type.makeVector();
1483 break;
1484 case EHTokMin16uint2:
1485 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1486 break;
1487 case EHTokMin16uint3:
1488 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1489 break;
1490 case EHTokMin16uint4:
1491 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1492 break;
1493
John Kessenich0133c122016-05-20 12:17:26 -06001494 case EHTokInt1x1:
1495 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1496 break;
1497 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001498 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001499 break;
1500 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001501 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001502 break;
1503 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001504 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001505 break;
1506 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001507 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001508 break;
1509 case EHTokInt2x2:
1510 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1511 break;
1512 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001513 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001514 break;
1515 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001516 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001517 break;
1518 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001519 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001520 break;
1521 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001522 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001523 break;
1524 case EHTokInt3x3:
1525 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1526 break;
1527 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001528 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001529 break;
1530 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001531 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001532 break;
1533 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001534 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001535 break;
1536 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001537 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001538 break;
1539 case EHTokInt4x4:
1540 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1541 break;
1542
John Kessenich71351de2016-06-08 12:50:56 -06001543 case EHTokUint1x1:
1544 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1545 break;
1546 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001547 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001548 break;
1549 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001550 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001551 break;
1552 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001553 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001554 break;
1555 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001556 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001557 break;
1558 case EHTokUint2x2:
1559 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1560 break;
1561 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001562 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001563 break;
1564 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001565 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001566 break;
1567 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001568 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001569 break;
1570 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001571 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001572 break;
1573 case EHTokUint3x3:
1574 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1575 break;
1576 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001577 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001578 break;
1579 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001580 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001581 break;
1582 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001583 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001584 break;
1585 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001586 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001587 break;
1588 case EHTokUint4x4:
1589 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1590 break;
1591
1592 case EHTokBool1x1:
1593 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1594 break;
1595 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001596 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001597 break;
1598 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001599 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001600 break;
1601 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001603 break;
1604 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001605 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001606 break;
1607 case EHTokBool2x2:
1608 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1609 break;
1610 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001611 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001612 break;
1613 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001614 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001615 break;
1616 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001618 break;
1619 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001621 break;
1622 case EHTokBool3x3:
1623 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1624 break;
1625 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001626 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001627 break;
1628 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001629 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001630 break;
1631 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001632 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001633 break;
1634 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001635 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001636 break;
1637 case EHTokBool4x4:
1638 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1639 break;
1640
John Kessenich0133c122016-05-20 12:17:26 -06001641 case EHTokFloat1x1:
1642 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1643 break;
1644 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001645 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001646 break;
1647 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001648 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001649 break;
1650 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001651 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001652 break;
1653 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001654 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001655 break;
John Kessenich87142c72016-03-12 20:24:24 -07001656 case EHTokFloat2x2:
1657 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1658 break;
1659 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001660 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001661 break;
1662 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001663 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001664 break;
John Kessenich0133c122016-05-20 12:17:26 -06001665 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001666 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001667 break;
John Kessenich87142c72016-03-12 20:24:24 -07001668 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001669 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001670 break;
1671 case EHTokFloat3x3:
1672 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1673 break;
1674 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001675 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001676 break;
John Kessenich0133c122016-05-20 12:17:26 -06001677 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001678 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001679 break;
John Kessenich87142c72016-03-12 20:24:24 -07001680 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001681 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001682 break;
1683 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001684 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001685 break;
1686 case EHTokFloat4x4:
1687 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1688 break;
1689
John Kessenich0133c122016-05-20 12:17:26 -06001690 case EHTokDouble1x1:
1691 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1692 break;
1693 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001694 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001695 break;
1696 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001697 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001698 break;
1699 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001700 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001701 break;
1702 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001703 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001704 break;
1705 case EHTokDouble2x2:
1706 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1707 break;
1708 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001709 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001710 break;
1711 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001712 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001713 break;
1714 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001715 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001716 break;
1717 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001718 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001719 break;
1720 case EHTokDouble3x3:
1721 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1722 break;
1723 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001724 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001725 break;
1726 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001727 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001728 break;
1729 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001730 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001731 break;
1732 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001733 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001734 break;
1735 case EHTokDouble4x4:
1736 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1737 break;
1738
John Kessenich87142c72016-03-12 20:24:24 -07001739 default:
1740 return false;
1741 }
1742
1743 advanceToken();
1744
1745 return true;
1746}
1747
John Kesseniche6e74942016-06-11 16:43:14 -06001748// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001749// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1750// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001751// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001752//
1753// struct_type
1754// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001755// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001756// | CBUFFER
1757// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001758//
John Kessenich54ee28f2017-03-11 14:13:00 -07001759bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001760{
John Kessenichb804de62016-09-05 12:19:18 -06001761 // This storage qualifier will tell us whether it's an AST
1762 // block type or just a generic structure type.
1763 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001764
1765 // CBUFFER
1766 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001767 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001768 // TBUFFER
1769 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001770 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001771 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001772 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001773 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001774 return false;
1775
1776 // IDENTIFIER
1777 TString structName = "";
1778 if (peekTokenClass(EHTokIdentifier)) {
1779 structName = *token.string;
1780 advanceToken();
1781 }
1782
John Kessenich3d157c52016-07-25 16:05:33 -06001783 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001784 TQualifier postDeclQualifier;
1785 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001786 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001787
John Kesseniche6e74942016-06-11 16:43:14 -06001788 // LEFT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001789 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001790 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001791 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1792 // struct_type IDENTIFIER
1793 return true;
1794 } else {
1795 expected("{");
1796 return false;
1797 }
John Kesseniche6e74942016-06-11 16:43:14 -06001798 }
1799
1800 // struct_declaration_list
1801 TTypeList* typeList;
John Kessenich54ee28f2017-03-11 14:13:00 -07001802 if (! acceptStructDeclarationList(typeList, nodeList, structName)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001803 expected("struct member declarations");
1804 return false;
1805 }
1806
1807 // RIGHT_BRACE
1808 if (! acceptTokenClass(EHTokRightBrace)) {
1809 expected("}");
1810 return false;
1811 }
1812
1813 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001814 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001815 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001816 else {
John Kessenich7735b942016-09-05 12:40:06 -06001817 postDeclQualifier.storage = storageQualifier;
1818 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001819 }
John Kesseniche6e74942016-06-11 16:43:14 -06001820
John Kessenich727b3742017-02-03 17:57:55 -07001821 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001822
1823 return true;
1824}
1825
steve-lunarg5da1f032017-02-12 17:50:28 -07001826// struct_buffer
1827// : APPENDSTRUCTUREDBUFFER
1828// | BYTEADDRESSBUFFER
1829// | CONSUMESTRUCTUREDBUFFER
1830// | RWBYTEADDRESSBUFFER
1831// | RWSTRUCTUREDBUFFER
1832// | STRUCTUREDBUFFER
1833bool HlslGrammar::acceptStructBufferType(TType& type)
1834{
1835 const EHlslTokenClass structBuffType = peek();
1836
1837 // TODO: globallycoherent
1838 bool hasTemplateType = true;
1839 bool readonly = false;
1840
1841 TStorageQualifier storage = EvqBuffer;
1842
1843 switch (structBuffType) {
1844 case EHTokAppendStructuredBuffer:
1845 unimplemented("AppendStructuredBuffer");
1846 return false;
1847 case EHTokByteAddressBuffer:
1848 hasTemplateType = false;
1849 readonly = true;
1850 break;
1851 case EHTokConsumeStructuredBuffer:
1852 unimplemented("ConsumeStructuredBuffer");
1853 return false;
1854 case EHTokRWByteAddressBuffer:
1855 hasTemplateType = false;
1856 break;
1857 case EHTokRWStructuredBuffer:
1858 break;
1859 case EHTokStructuredBuffer:
1860 readonly = true;
1861 break;
1862 default:
1863 return false; // not a structure buffer type
1864 }
1865
1866 advanceToken(); // consume the structure keyword
1867
1868 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1869 TType* templateType = new TType;
1870
1871 if (hasTemplateType) {
1872 if (! acceptTokenClass(EHTokLeftAngle)) {
1873 expected("left angle bracket");
1874 return false;
1875 }
1876
1877 if (! acceptType(*templateType)) {
1878 expected("type");
1879 return false;
1880 }
1881 if (! acceptTokenClass(EHTokRightAngle)) {
1882 expected("right angle bracket");
1883 return false;
1884 }
1885 } else {
1886 // byte address buffers have no explicit type.
1887 TType uintType(EbtUint, storage);
1888 templateType->shallowCopy(uintType);
1889 }
1890
1891 // Create an unsized array out of that type.
1892 // TODO: does this work if it's already an array type?
1893 TArraySizes unsizedArray;
1894 unsizedArray.addInnerSize(UnsizedArraySize);
1895 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07001896 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07001897
1898 // field name is canonical for all structbuffers
1899 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07001900
1901 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07001902
steve-lunarg5da1f032017-02-12 17:50:28 -07001903 TTypeList* blockStruct = new TTypeList;
1904 TTypeLoc member = { templateType, token.loc };
1905 blockStruct->push_back(member);
1906
steve-lunargdd8287a2017-02-23 18:04:12 -07001907 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07001908 TType blockType(blockStruct, "", templateType->getQualifier());
1909
steve-lunargdd8287a2017-02-23 18:04:12 -07001910 blockType.getQualifier().storage = storage;
1911 blockType.getQualifier().readonly = readonly;
1912
1913 // We may have created an equivalent type before, in which case we should use its
1914 // deep structure.
1915 parseContext.shareStructBufferType(blockType);
1916
steve-lunarg5da1f032017-02-12 17:50:28 -07001917 type.shallowCopy(blockType);
1918
1919 return true;
1920}
1921
John Kesseniche6e74942016-06-11 16:43:14 -06001922// struct_declaration_list
1923// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1924//
1925// struct_declaration
1926// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001927// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06001928//
1929// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001930// : IDENTIFIER post_decls
1931// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07001932// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06001933//
John Kessenich54ee28f2017-03-11 14:13:00 -07001934bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, const TString& typeName)
John Kesseniche6e74942016-06-11 16:43:14 -06001935{
1936 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001937 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001938
1939 do {
1940 // success on seeing the RIGHT_BRACE coming up
1941 if (peekTokenClass(EHTokRightBrace))
1942 return true;
1943
1944 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07001945
1946 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001947
1948 // fully_specified_type
1949 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07001950 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001951 expected("member type");
1952 return false;
1953 }
1954
1955 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001956 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001957 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001958 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001959 expected("member name");
1960 return false;
1961 }
1962
John Kessenich54ee28f2017-03-11 14:13:00 -07001963 if (peekTokenClass(EHTokLeftParen)) {
1964 // function_parameters
1965 if (!declarator_list) {
John Kessenich088d52b2017-03-11 17:55:28 -07001966 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, typeName, memberType,
1967 *idToken.string);
John Kessenich54ee28f2017-03-11 14:13:00 -07001968 if (functionDefinitionAccepted)
1969 break;
1970 }
1971 expected("member-function definition");
1972 return false;
1973 } else {
1974 // add it to the list of members
1975 TTypeLoc member = { new TType(EbtVoid), token.loc };
1976 member.type->shallowCopy(memberType);
1977 member.type->setFieldName(*idToken.string);
1978 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06001979
John Kessenich54ee28f2017-03-11 14:13:00 -07001980 // array_specifier
1981 TArraySizes* arraySizes = nullptr;
1982 acceptArraySpecifier(arraySizes);
1983 if (arraySizes)
1984 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001985
John Kessenich54ee28f2017-03-11 14:13:00 -07001986 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06001987
John Kessenich54ee28f2017-03-11 14:13:00 -07001988 // EQUAL assignment_expression
1989 if (acceptTokenClass(EHTokAssign)) {
1990 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
1991 TIntermTyped* expressionNode = nullptr;
1992 if (! acceptAssignmentExpression(expressionNode)) {
1993 expected("initializer");
1994 return false;
1995 }
John Kessenich18adbdb2017-02-02 15:16:20 -07001996 }
1997 }
John Kesseniche6e74942016-06-11 16:43:14 -06001998 // success on seeing the SEMICOLON coming up
1999 if (peekTokenClass(EHTokSemicolon))
2000 break;
2001
2002 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002003 if (acceptTokenClass(EHTokComma))
2004 declarator_list = true;
2005 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002006 expected(",");
2007 return false;
2008 }
2009
2010 } while (true);
2011
2012 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002013 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002014 expected(";");
2015 return false;
2016 }
2017
2018 } while (true);
2019}
2020
John Kessenich54ee28f2017-03-11 14:13:00 -07002021// member_function_definition
2022// | function_parameters post_decls compound_statement
2023//
2024// Expects type to have EvqGlobal for a static member and
2025// EvqTemporary for non-static member.
2026bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TString& typeName,
2027 const TType& type, const TString& memberName)
2028{
2029 // watch early returns...
2030 parseContext.pushThis(typeName);
2031 bool accepted = false;
2032
2033 TString* functionName = parseContext.getFullMemberFunctionName(memberName, type.getQualifier().storage == EvqGlobal);
John Kessenich088d52b2017-03-11 17:55:28 -07002034 TFunctionDeclarator declarator;
2035 declarator.function = new TFunction(functionName, type);
John Kessenich54ee28f2017-03-11 14:13:00 -07002036
2037 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002038 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002039 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002040 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002041
2042 // compound_statement (function body definition)
2043 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002044 if (declarator.function->getType().getQualifier().storage != EvqGlobal) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002045 expected("only static member functions are accepted");
2046 return false;
2047 }
2048
John Kessenich088d52b2017-03-11 17:55:28 -07002049 declarator.loc = token.loc;
2050 accepted = acceptFunctionDefinition(declarator, nodeList);
John Kessenich54ee28f2017-03-11 14:13:00 -07002051 }
2052 } else
2053 expected("function parameter list");
2054
2055 parseContext.popThis();
2056 return accepted;
2057}
2058
John Kessenich5f934b02016-03-13 17:58:25 -06002059// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002060// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002061// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002062//
2063bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2064{
John Kessenich078d7f22016-03-14 10:02:11 -06002065 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002066 if (! acceptTokenClass(EHTokLeftParen))
2067 return false;
2068
John Kessenich71351de2016-06-08 12:50:56 -06002069 // VOID RIGHT_PAREN
2070 if (! acceptTokenClass(EHTokVoid)) {
2071 do {
2072 // parameter_declaration
2073 if (! acceptParameterDeclaration(function))
2074 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002075
John Kessenich71351de2016-06-08 12:50:56 -06002076 // COMMA
2077 if (! acceptTokenClass(EHTokComma))
2078 break;
2079 } while (true);
2080 }
John Kessenich5f934b02016-03-13 17:58:25 -06002081
John Kessenich078d7f22016-03-14 10:02:11 -06002082 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002083 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002084 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002085 return false;
2086 }
2087
2088 return true;
2089}
2090
steve-lunarg26d31452016-12-23 18:56:57 -07002091// default_parameter_declaration
2092// : EQUAL conditional_expression
2093// : EQUAL initializer
2094bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2095{
2096 node = nullptr;
2097
2098 // Valid not to have a default_parameter_declaration
2099 if (!acceptTokenClass(EHTokAssign))
2100 return true;
2101
2102 if (!acceptConditionalExpression(node)) {
2103 if (!acceptInitializer(node))
2104 return false;
2105
2106 // For initializer lists, we have to const-fold into a constructor for the type, so build
2107 // that.
2108 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2109 if (constructor == nullptr) // cannot construct
2110 return false;
2111
2112 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002113 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002114 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002115
steve-lunarg26d31452016-12-23 18:56:57 -07002116 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2117 }
2118
2119 // If this is simply a constant, we can use it directly.
2120 if (node->getAsConstantUnion())
2121 return true;
2122
2123 // Otherwise, it has to be const-foldable.
2124 TIntermTyped* origNode = node;
2125
2126 node = intermediate.fold(node->getAsAggregate());
2127
2128 if (node != nullptr && origNode != node)
2129 return true;
2130
2131 parseContext.error(token.loc, "invalid default parameter value", "", "");
2132
2133 return false;
2134}
2135
John Kessenich5f934b02016-03-13 17:58:25 -06002136// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002137// : fully_specified_type post_decls [ = default_parameter_declaration ]
2138// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002139//
2140bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2141{
2142 // fully_specified_type
2143 TType* type = new TType;
2144 if (! acceptFullySpecifiedType(*type))
2145 return false;
2146
2147 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002148 HlslToken idToken;
2149 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002150
John Kessenich19b92ff2016-06-19 11:50:34 -06002151 // array_specifier
2152 TArraySizes* arraySizes = nullptr;
2153 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002154 if (arraySizes) {
2155 if (arraySizes->isImplicit()) {
2156 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2157 return false;
2158 }
2159
John Kessenich19b92ff2016-06-19 11:50:34 -06002160 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002161 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002162
2163 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002164 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002165
steve-lunarg26d31452016-12-23 18:56:57 -07002166 TIntermTyped* defaultValue;
2167 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2168 return false;
2169
John Kessenich5aa59e22016-06-17 15:50:47 -06002170 parseContext.paramFix(*type);
2171
steve-lunarg26d31452016-12-23 18:56:57 -07002172 // If any prior parameters have default values, all the parameters after that must as well.
2173 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2174 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2175 return false;
2176 }
2177
2178 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002179 function.addParameter(param);
2180
2181 return true;
2182}
2183
2184// Do the work to create the function definition in addition to
2185// parsing the body (compound_statement).
John Kessenich088d52b2017-03-11 17:55:28 -07002186bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
John Kessenich5f934b02016-03-13 17:58:25 -06002187{
John Kessenich088d52b2017-03-11 17:55:28 -07002188 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002189
John Kessenich088d52b2017-03-11 17:55:28 -07002190 return acceptFunctionBody(declarator, nodeList);
2191}
2192
2193bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2194{
2195 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002196 TIntermNode* entryPointNode = nullptr;
2197
John Kessenich077e0522016-06-09 02:02:17 -06002198 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002199 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2200 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002201
2202 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002203 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002204 if (! acceptCompoundStatement(functionBody))
2205 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002206
John Kessenich54ee28f2017-03-11 14:13:00 -07002207 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002208 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002209
2210 // Hook up the 1 or 2 function definitions.
2211 nodeList = intermediate.growAggregate(nodeList, functionNode);
2212 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002213
2214 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002215}
2216
John Kessenich0d2b6de2016-06-05 11:23:11 -06002217// Accept an expression with parenthesis around it, where
2218// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002219// syntactically required ones like in "if ( expression )".
2220//
2221// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002222//
2223// Note this one is not set up to be speculative; as it gives
2224// errors if not found.
2225//
2226bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2227{
2228 // LEFT_PAREN
2229 if (! acceptTokenClass(EHTokLeftParen))
2230 expected("(");
2231
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002232 bool decl = false;
2233 TIntermNode* declNode = nullptr;
2234 decl = acceptControlDeclaration(declNode);
2235 if (decl) {
2236 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2237 expected("initialized declaration");
2238 return false;
2239 } else
2240 expression = declNode->getAsTyped();
2241 } else {
2242 // no declaration
2243 if (! acceptExpression(expression)) {
2244 expected("expression");
2245 return false;
2246 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002247 }
2248
2249 // RIGHT_PAREN
2250 if (! acceptTokenClass(EHTokRightParen))
2251 expected(")");
2252
2253 return true;
2254}
2255
John Kessenich34fb0362016-05-03 23:17:20 -06002256// The top-level full expression recognizer.
2257//
John Kessenich87142c72016-03-12 20:24:24 -07002258// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002259// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002260//
2261bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2262{
LoopDawgef764a22016-06-03 09:17:51 -06002263 node = nullptr;
2264
John Kessenich34fb0362016-05-03 23:17:20 -06002265 // assignment_expression
2266 if (! acceptAssignmentExpression(node))
2267 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002268
John Kessenich34fb0362016-05-03 23:17:20 -06002269 if (! peekTokenClass(EHTokComma))
2270 return true;
2271
2272 do {
2273 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002274 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002275 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002276
John Kessenich34fb0362016-05-03 23:17:20 -06002277 // ... assignment_expression
2278 TIntermTyped* rightNode = nullptr;
2279 if (! acceptAssignmentExpression(rightNode)) {
2280 expected("assignment expression");
2281 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002282 }
2283
John Kessenich34fb0362016-05-03 23:17:20 -06002284 node = intermediate.addComma(node, rightNode, loc);
2285
2286 if (! peekTokenClass(EHTokComma))
2287 return true;
2288 } while (true);
2289}
2290
John Kessenich07354242016-07-01 19:58:06 -06002291// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002292// : LEFT_BRACE RIGHT_BRACE
2293// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002294//
2295// initializer_list
2296// : assignment_expression COMMA assignment_expression COMMA ...
2297//
2298bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2299{
2300 // LEFT_BRACE
2301 if (! acceptTokenClass(EHTokLeftBrace))
2302 return false;
2303
John Kessenich98ad4852016-11-27 17:39:07 -07002304 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002305 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002306 if (acceptTokenClass(EHTokRightBrace)) {
2307 // a zero-length initializer list
2308 node = intermediate.makeAggregate(loc);
2309 return true;
2310 }
2311
2312 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002313 node = nullptr;
2314 do {
2315 // assignment_expression
2316 TIntermTyped* expr;
2317 if (! acceptAssignmentExpression(expr)) {
2318 expected("assignment expression in initializer list");
2319 return false;
2320 }
2321 node = intermediate.growAggregate(node, expr, loc);
2322
2323 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002324 if (acceptTokenClass(EHTokComma)) {
2325 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2326 return true;
John Kessenich07354242016-07-01 19:58:06 -06002327 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002328 }
John Kessenich07354242016-07-01 19:58:06 -06002329
2330 // RIGHT_BRACE
2331 if (acceptTokenClass(EHTokRightBrace))
2332 return true;
2333
2334 expected(", or }");
2335 return false;
2336 } while (true);
2337}
2338
John Kessenich34fb0362016-05-03 23:17:20 -06002339// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002340// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002341//
2342// a op (b op (c op d))
2343//
2344// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002345// : initializer
2346// | conditional_expression
2347// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002348//
2349bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2350{
John Kessenich07354242016-07-01 19:58:06 -06002351 // initializer
2352 if (peekTokenClass(EHTokLeftBrace)) {
2353 if (acceptInitializer(node))
2354 return true;
2355
2356 expected("initializer");
2357 return false;
2358 }
2359
John Kessenich00957f82016-07-27 10:39:57 -06002360 // conditional_expression
2361 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002362 return false;
2363
John Kessenich07354242016-07-01 19:58:06 -06002364 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002365 TOperator assignOp = HlslOpMap::assignment(peek());
2366 if (assignOp == EOpNull)
2367 return true;
2368
John Kessenich00957f82016-07-27 10:39:57 -06002369 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002370 TSourceLoc loc = token.loc;
2371 advanceToken();
2372
John Kessenich00957f82016-07-27 10:39:57 -06002373 // conditional_expression assign_op conditional_expression ...
2374 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002375 // gets the right-to-left associativity.
2376 TIntermTyped* rightNode = nullptr;
2377 if (! acceptAssignmentExpression(rightNode)) {
2378 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002379 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002380 }
2381
John Kessenichd21baed2016-09-16 03:05:12 -06002382 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002383 node = parseContext.handleLvalue(loc, "assign", node);
2384
John Kessenichfea226b2016-07-28 17:53:56 -06002385 if (node == nullptr) {
2386 parseContext.error(loc, "could not create assignment", "", "");
2387 return false;
2388 }
John Kessenich34fb0362016-05-03 23:17:20 -06002389
2390 if (! peekTokenClass(EHTokComma))
2391 return true;
2392
2393 return true;
2394}
2395
John Kessenich00957f82016-07-27 10:39:57 -06002396// Accept a conditional expression, which associates right-to-left,
2397// accomplished by the "true" expression calling down to lower
2398// precedence levels than this level.
2399//
2400// conditional_expression
2401// : binary_expression
2402// | binary_expression QUESTION expression COLON assignment_expression
2403//
2404bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2405{
2406 // binary_expression
2407 if (! acceptBinaryExpression(node, PlLogicalOr))
2408 return false;
2409
2410 if (! acceptTokenClass(EHTokQuestion))
2411 return true;
2412
2413 TIntermTyped* trueNode = nullptr;
2414 if (! acceptExpression(trueNode)) {
2415 expected("expression after ?");
2416 return false;
2417 }
2418 TSourceLoc loc = token.loc;
2419
2420 if (! acceptTokenClass(EHTokColon)) {
2421 expected(":");
2422 return false;
2423 }
2424
2425 TIntermTyped* falseNode = nullptr;
2426 if (! acceptAssignmentExpression(falseNode)) {
2427 expected("expression after :");
2428 return false;
2429 }
2430
2431 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2432
2433 return true;
2434}
2435
John Kessenich34fb0362016-05-03 23:17:20 -06002436// Accept a binary expression, for binary operations that
2437// associate left-to-right. This is, it is implicit, for example
2438//
2439// ((a op b) op c) op d
2440//
2441// binary_expression
2442// : expression op expression op expression ...
2443//
2444// where 'expression' is the next higher level in precedence.
2445//
2446bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2447{
2448 if (precedenceLevel > PlMul)
2449 return acceptUnaryExpression(node);
2450
2451 // assignment_expression
2452 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2453 return false;
2454
John Kessenich34fb0362016-05-03 23:17:20 -06002455 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002456 TOperator op = HlslOpMap::binary(peek());
2457 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2458 if (tokenLevel < precedenceLevel)
2459 return true;
2460
John Kessenich34fb0362016-05-03 23:17:20 -06002461 // ... op
2462 TSourceLoc loc = token.loc;
2463 advanceToken();
2464
2465 // ... expression
2466 TIntermTyped* rightNode = nullptr;
2467 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2468 expected("expression");
2469 return false;
2470 }
2471
2472 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002473 if (node == nullptr) {
2474 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2475 return false;
2476 }
John Kessenich34fb0362016-05-03 23:17:20 -06002477 } while (true);
2478}
2479
2480// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002481// : (type) unary_expression
2482// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002483// | - unary_expression
2484// | ! unary_expression
2485// | ~ unary_expression
2486// | ++ unary_expression
2487// | -- unary_expression
2488// | postfix_expression
2489//
2490bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2491{
John Kessenich1cc1a282016-06-03 16:55:49 -06002492 // (type) unary_expression
2493 // Have to look two steps ahead, because this could be, e.g., a
2494 // postfix_expression instead, since that also starts with at "(".
2495 if (acceptTokenClass(EHTokLeftParen)) {
2496 TType castType;
2497 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002498 if (acceptTokenClass(EHTokRightParen)) {
2499 // We've matched "(type)" now, get the expression to cast
2500 TSourceLoc loc = token.loc;
2501 if (! acceptUnaryExpression(node))
2502 return false;
2503
2504 // Hook it up like a constructor
2505 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2506 if (constructorFunction == nullptr) {
2507 expected("type that can be constructed");
2508 return false;
2509 }
2510 TIntermTyped* arguments = nullptr;
2511 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2512 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2513
2514 return true;
2515 } else {
2516 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2517 // the '(int' part. We must back up twice.
2518 recedeToken();
2519 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002520 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002521 } else {
2522 // This isn't a type cast, but it still started "(", so if it is a
2523 // unary expression, it can only be a postfix_expression, so try that.
2524 // Back it up first.
2525 recedeToken();
2526 return acceptPostfixExpression(node);
2527 }
2528 }
2529
2530 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002531 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002532
John Kessenich1cc1a282016-06-03 16:55:49 -06002533 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002534 if (unaryOp == EOpNull)
2535 return acceptPostfixExpression(node);
2536
2537 // op unary_expression
2538 TSourceLoc loc = token.loc;
2539 advanceToken();
2540 if (! acceptUnaryExpression(node))
2541 return false;
2542
2543 // + is a no-op
2544 if (unaryOp == EOpAdd)
2545 return true;
2546
2547 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002548
2549 // These unary ops require lvalues
2550 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2551 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002552
2553 return node != nullptr;
2554}
2555
2556// postfix_expression
2557// : LEFT_PAREN expression RIGHT_PAREN
2558// | literal
2559// | constructor
2560// | identifier
2561// | function_call
2562// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2563// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002564// | postfix_expression DOT IDENTIFIER arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002565// | postfix_expression COLONCOLON IDENTIFIER arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002566// | postfix_expression INC_OP
2567// | postfix_expression DEC_OP
2568//
2569bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2570{
2571 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002572 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002573
2574 // idToken will pick up either a variable or a function name in a function call
2575 HlslToken idToken;
2576
John Kessenich54ee28f2017-03-11 14:13:00 -07002577 // scopeBase will pick up the type symbol on the left of '::'
2578 TSymbol* scopeBase = nullptr;
2579
John Kessenich21472ae2016-06-04 11:46:33 -06002580 // Find something before the postfix operations, as they can't operate
2581 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002582 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002583 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002584 if (! acceptExpression(node)) {
2585 expected("expression");
2586 return false;
2587 }
2588 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002589 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002590 return false;
2591 }
John Kessenich34fb0362016-05-03 23:17:20 -06002592 } else if (acceptLiteral(node)) {
John Kessenichecba76f2017-01-06 00:34:48 -07002593 // literal (nothing else to do yet), go on to the
John Kessenich34fb0362016-05-03 23:17:20 -06002594 } else if (acceptConstructor(node)) {
2595 // constructor (nothing else to do yet)
2596 } else if (acceptIdentifier(idToken)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002597 // user-type, identifier, or function name
2598 if (peekTokenClass(EHTokColonColon)) {
2599 TType type;
2600 scopeBase = parseContext.lookupUserType(*idToken.string, type);
2601 if (scopeBase == nullptr) {
2602 expected("type left of ::");
2603 return false;
2604 }
2605 } else if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002606 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002607 } else if (acceptFunctionCall(idToken, node)) {
2608 // function_call (nothing else to do yet)
2609 } else {
2610 expected("function call arguments");
2611 return false;
2612 }
John Kessenich21472ae2016-06-04 11:46:33 -06002613 } else {
2614 // nothing found, can't post operate
2615 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002616 }
2617
steve-lunarga2b01a02016-11-28 17:09:54 -07002618 // This is to guarantee we do this no matter how we get out of the stack frame.
2619 // This way there's no bug if an early return forgets to do it.
2620 struct tFinalize {
2621 tFinalize(HlslParseContext& p) : parseContext(p) { }
2622 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002623 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002624 private:
John Kessenichca71d942017-03-07 20:44:09 -07002625 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002626 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002627 } finalize(parseContext);
2628
2629 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2630 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2631 // level: hence the init and finalize. Even though in practice these must be
2632 // constants, they are parsed no matter what.
2633 parseContext.initFlattening();
2634
John Kessenich21472ae2016-06-04 11:46:33 -06002635 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002636 do {
2637 TSourceLoc loc = token.loc;
2638 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002639
John Kessenich34fb0362016-05-03 23:17:20 -06002640 // Consume only a valid post-unary operator, otherwise we are done.
2641 switch (postOp) {
2642 case EOpIndexDirectStruct:
2643 case EOpIndexIndirect:
2644 case EOpPostIncrement:
2645 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002646 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002647 advanceToken();
2648 break;
2649 default:
2650 return true;
2651 }
John Kessenich87142c72016-03-12 20:24:24 -07002652
John Kessenich34fb0362016-05-03 23:17:20 -06002653 // We have a valid post-unary operator, process it.
2654 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002655 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002656 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002657 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002658 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002659 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002660 HlslToken field;
2661 if (! acceptIdentifier(field)) {
2662 expected("swizzle or member");
2663 return false;
2664 }
LoopDawg4886f692016-06-29 10:58:58 -06002665
John Kessenich516d92d2017-03-08 20:09:03 -07002666 if (peekTokenClass(EHTokLeftParen)) {
2667 // member function
2668 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002669
John Kessenich516d92d2017-03-08 20:09:03 -07002670 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002671 if (! acceptFunctionCall(field, node, thisNode, scopeBase)) {
LoopDawg4886f692016-06-29 10:58:58 -06002672 expected("function parameters");
2673 return false;
2674 }
John Kessenich516d92d2017-03-08 20:09:03 -07002675 } else
2676 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002677
John Kessenich34fb0362016-05-03 23:17:20 -06002678 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002679 }
John Kessenich34fb0362016-05-03 23:17:20 -06002680 case EOpIndexIndirect:
2681 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002682 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002683 TIntermTyped* indexNode = nullptr;
2684 if (! acceptExpression(indexNode) ||
2685 ! peekTokenClass(EHTokRightBracket)) {
2686 expected("expression followed by ']'");
2687 return false;
2688 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002689 advanceToken();
2690 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2691 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002692 }
2693 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002694 // INC_OP
2695 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002696 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002697 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002698 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002699 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002700 break;
2701 default:
2702 assert(0);
2703 break;
2704 }
2705 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002706}
2707
John Kessenichd016be12016-03-13 11:24:20 -06002708// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002709// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002710//
2711bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2712{
2713 // type
2714 TType type;
2715 if (acceptType(type)) {
2716 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2717 if (constructorFunction == nullptr)
2718 return false;
2719
2720 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002721 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002722 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002723 // It's possible this is a type keyword used as an identifier. Put the token back
2724 // for later use.
2725 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002726 return false;
2727 }
2728
2729 // hook it up
2730 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2731
2732 return true;
2733 }
2734
2735 return false;
2736}
2737
John Kessenich34fb0362016-05-03 23:17:20 -06002738// The function_call identifier was already recognized, and passed in as idToken.
2739//
2740// function_call
2741// : [idToken] arguments
2742//
John Kessenich54ee28f2017-03-11 14:13:00 -07002743bool HlslGrammar::acceptFunctionCall(HlslToken callToken, TIntermTyped*& node, TIntermTyped* baseObject,
2744 const TSymbol* baseType)
John Kessenich34fb0362016-05-03 23:17:20 -06002745{
John Kessenich54ee28f2017-03-11 14:13:00 -07002746 // name
2747 TString* functionName = nullptr;
2748 if ((baseObject == nullptr && baseType == nullptr)
2749 || parseContext.isBuiltInMethod(callToken.loc, baseObject, *callToken.string))
2750 functionName = callToken.string;
2751 else {
2752 functionName = NewPoolTString("");
2753 if (baseObject != nullptr) {
2754 functionName->append(baseObject->getType().getTypeName().c_str());
2755 functionName->append(".");
2756 } else if (baseType != nullptr) {
2757 functionName->append(baseType->getType().getTypeName());
2758 functionName->append("::");
John Kessenich5f12d2f2017-03-11 09:39:55 -07002759 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002760 functionName->append(*callToken.string);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002761 }
LoopDawg4886f692016-06-29 10:58:58 -06002762
John Kessenich54ee28f2017-03-11 14:13:00 -07002763 // function
2764 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2765
2766 // arguments
2767 // Non-static member functions have an implicit first argument of the base object.
2768 TIntermTyped* arguments = nullptr;
2769 if (baseObject != nullptr)
2770 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenich4678ca92016-05-13 09:33:42 -06002771 if (! acceptArguments(function, arguments))
2772 return false;
2773
John Kessenich54ee28f2017-03-11 14:13:00 -07002774 // call
John Kessenich5f12d2f2017-03-11 09:39:55 -07002775 node = parseContext.handleFunctionCall(callToken.loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002776
2777 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002778}
2779
John Kessenich87142c72016-03-12 20:24:24 -07002780// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002781// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002782//
John Kessenichd016be12016-03-13 11:24:20 -06002783// The arguments are pushed onto the 'function' argument list and
2784// onto the 'arguments' aggregate.
2785//
John Kessenich4678ca92016-05-13 09:33:42 -06002786bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002787{
John Kessenich078d7f22016-03-14 10:02:11 -06002788 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002789 if (! acceptTokenClass(EHTokLeftParen))
2790 return false;
2791
2792 do {
John Kessenichd016be12016-03-13 11:24:20 -06002793 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002794 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002795 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002796 break;
John Kessenichd016be12016-03-13 11:24:20 -06002797
2798 // hook it up
2799 parseContext.handleFunctionArgument(function, arguments, arg);
2800
John Kessenich078d7f22016-03-14 10:02:11 -06002801 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002802 if (! acceptTokenClass(EHTokComma))
2803 break;
2804 } while (true);
2805
John Kessenich078d7f22016-03-14 10:02:11 -06002806 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002807 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002808 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002809 return false;
2810 }
2811
2812 return true;
2813}
2814
2815bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2816{
2817 switch (token.tokenClass) {
2818 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002819 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002820 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002821 case EHTokUintConstant:
2822 node = intermediate.addConstantUnion(token.u, token.loc, true);
2823 break;
John Kessenich87142c72016-03-12 20:24:24 -07002824 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002825 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002826 break;
2827 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002828 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002829 break;
2830 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002831 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002832 break;
John Kessenich86f71382016-09-19 20:23:18 -06002833 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002834 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002835 break;
John Kessenich87142c72016-03-12 20:24:24 -07002836
2837 default:
2838 return false;
2839 }
2840
2841 advanceToken();
2842
2843 return true;
2844}
2845
John Kessenich5f934b02016-03-13 17:58:25 -06002846// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002847// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002848//
John Kessenich21472ae2016-06-04 11:46:33 -06002849bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002850{
John Kessenich21472ae2016-06-04 11:46:33 -06002851 TIntermAggregate* compoundStatement = nullptr;
2852
John Kessenich34fb0362016-05-03 23:17:20 -06002853 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002854 if (! acceptTokenClass(EHTokLeftBrace))
2855 return false;
2856
2857 // statement statement ...
2858 TIntermNode* statement = nullptr;
2859 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002860 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2861 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2862 branch->getFlowOp() == EOpDefault)) {
2863 // hook up individual subsequences within a switch statement
2864 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2865 compoundStatement = nullptr;
2866 } else {
2867 // hook it up to the growing compound statement
2868 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2869 }
John Kessenich5f934b02016-03-13 17:58:25 -06002870 }
John Kessenich34fb0362016-05-03 23:17:20 -06002871 if (compoundStatement)
2872 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002873
John Kessenich21472ae2016-06-04 11:46:33 -06002874 retStatement = compoundStatement;
2875
John Kessenich34fb0362016-05-03 23:17:20 -06002876 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002877 return acceptTokenClass(EHTokRightBrace);
2878}
2879
John Kessenich0d2b6de2016-06-05 11:23:11 -06002880bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2881{
2882 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002883 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002884 parseContext.popScope();
2885
2886 return result;
2887}
2888
John Kessenich077e0522016-06-09 02:02:17 -06002889bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002890{
John Kessenich077e0522016-06-09 02:02:17 -06002891 parseContext.pushScope();
2892 bool result = acceptCompoundStatement(statement);
2893 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002894
2895 return result;
2896}
2897
John Kessenich5f934b02016-03-13 17:58:25 -06002898// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002899// : attributes attributed_statement
2900//
2901// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002902// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002903// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002904// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002905// | declaration_statement
2906// | selection_statement
2907// | switch_statement
2908// | case_label
2909// | iteration_statement
2910// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002911//
2912bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2913{
John Kessenich21472ae2016-06-04 11:46:33 -06002914 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002915
John Kessenich21472ae2016-06-04 11:46:33 -06002916 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002917 TAttributeMap attributes;
2918 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002919
John Kessenich21472ae2016-06-04 11:46:33 -06002920 // attributed_statement
2921 switch (peek()) {
2922 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002923 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002924
John Kessenich21472ae2016-06-04 11:46:33 -06002925 case EHTokIf:
2926 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002927
John Kessenich21472ae2016-06-04 11:46:33 -06002928 case EHTokSwitch:
2929 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002930
John Kessenich21472ae2016-06-04 11:46:33 -06002931 case EHTokFor:
2932 case EHTokDo:
2933 case EHTokWhile:
2934 return acceptIterationStatement(statement);
2935
2936 case EHTokContinue:
2937 case EHTokBreak:
2938 case EHTokDiscard:
2939 case EHTokReturn:
2940 return acceptJumpStatement(statement);
2941
2942 case EHTokCase:
2943 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002944 case EHTokDefault:
2945 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002946
2947 case EHTokSemicolon:
2948 return acceptTokenClass(EHTokSemicolon);
2949
2950 case EHTokRightBrace:
2951 // Performance: not strictly necessary, but stops a bunch of hunting early,
2952 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002953 return false;
2954
John Kessenich21472ae2016-06-04 11:46:33 -06002955 default:
2956 {
2957 // declaration
2958 if (acceptDeclaration(statement))
2959 return true;
2960
2961 // expression
2962 TIntermTyped* node;
2963 if (acceptExpression(node))
2964 statement = node;
2965 else
2966 return false;
2967
2968 // SEMICOLON (following an expression)
2969 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002970 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002971 return false;
2972 }
2973 }
2974 }
2975
John Kessenich5f934b02016-03-13 17:58:25 -06002976 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002977}
2978
John Kessenich21472ae2016-06-04 11:46:33 -06002979// attributes
2980// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2981//
2982// attribute:
2983// : UNROLL
2984// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2985// | FASTOPT
2986// | ALLOW_UAV_CONDITION
2987// | BRANCH
2988// | FLATTEN
2989// | FORCECASE
2990// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06002991// | DOMAIN
2992// | EARLYDEPTHSTENCIL
2993// | INSTANCE
2994// | MAXTESSFACTOR
2995// | OUTPUTCONTROLPOINTS
2996// | OUTPUTTOPOLOGY
2997// | PARTITIONING
2998// | PATCHCONSTANTFUNC
2999// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003000//
steve-lunarg1868b142016-10-20 13:07:10 -06003001void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003002{
steve-lunarg1868b142016-10-20 13:07:10 -06003003 // For now, accept the [ XXX(X) ] syntax, but drop all but
3004 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003005 // TODO: subset to correct set? Pass on?
3006 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003007 HlslToken idToken;
3008
John Kessenich0d2b6de2016-06-05 11:23:11 -06003009 // LEFT_BRACKET?
3010 if (! acceptTokenClass(EHTokLeftBracket))
3011 return;
3012
3013 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003014 if (acceptIdentifier(idToken)) {
3015 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003016 } else if (! peekTokenClass(EHTokRightBracket)) {
3017 expected("identifier");
3018 advanceToken();
3019 }
3020
steve-lunarga22f7db2016-11-11 08:17:44 -07003021 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003022
3023 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003024 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003025 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003026
John Kessenich0d2b6de2016-06-05 11:23:11 -06003027 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003028 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003029
steve-lunarga22f7db2016-11-11 08:17:44 -07003030 while (acceptAssignmentExpression(node)) {
3031 expectingExpression = false;
3032 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003033 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003034 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003035 }
3036
steve-lunarga22f7db2016-11-11 08:17:44 -07003037 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003038 if (! acceptTokenClass(EHTokRightParen))
3039 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003040
3041 // Error for partial or missing expression
3042 if (expectingExpression || expressions->getSequence().empty())
3043 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003044 }
3045
3046 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003047 if (!acceptTokenClass(EHTokRightBracket)) {
3048 expected("]");
3049 return;
3050 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003051
steve-lunarg1868b142016-10-20 13:07:10 -06003052 // Add any values we found into the attribute map. This accepts
3053 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003054 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003055 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003056}
3057
John Kessenich0d2b6de2016-06-05 11:23:11 -06003058// selection_statement
3059// : IF LEFT_PAREN expression RIGHT_PAREN statement
3060// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3061//
John Kessenich21472ae2016-06-04 11:46:33 -06003062bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3063{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003064 TSourceLoc loc = token.loc;
3065
3066 // IF
3067 if (! acceptTokenClass(EHTokIf))
3068 return false;
3069
3070 // so that something declared in the condition is scoped to the lifetimes
3071 // of the then-else statements
3072 parseContext.pushScope();
3073
3074 // LEFT_PAREN expression RIGHT_PAREN
3075 TIntermTyped* condition;
3076 if (! acceptParenExpression(condition))
3077 return false;
3078
3079 // create the child statements
3080 TIntermNodePair thenElse = { nullptr, nullptr };
3081
3082 // then statement
3083 if (! acceptScopedStatement(thenElse.node1)) {
3084 expected("then statement");
3085 return false;
3086 }
3087
3088 // ELSE
3089 if (acceptTokenClass(EHTokElse)) {
3090 // else statement
3091 if (! acceptScopedStatement(thenElse.node2)) {
3092 expected("else statement");
3093 return false;
3094 }
3095 }
3096
3097 // Put the pieces together
3098 statement = intermediate.addSelection(condition, thenElse, loc);
3099 parseContext.popScope();
3100
3101 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003102}
3103
John Kessenichd02dc5d2016-07-01 00:04:11 -06003104// switch_statement
3105// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3106//
John Kessenich21472ae2016-06-04 11:46:33 -06003107bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3108{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003109 // SWITCH
3110 TSourceLoc loc = token.loc;
3111 if (! acceptTokenClass(EHTokSwitch))
3112 return false;
3113
3114 // LEFT_PAREN expression RIGHT_PAREN
3115 parseContext.pushScope();
3116 TIntermTyped* switchExpression;
3117 if (! acceptParenExpression(switchExpression)) {
3118 parseContext.popScope();
3119 return false;
3120 }
3121
3122 // compound_statement
3123 parseContext.pushSwitchSequence(new TIntermSequence);
3124 bool statementOkay = acceptCompoundStatement(statement);
3125 if (statementOkay)
3126 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3127
3128 parseContext.popSwitchSequence();
3129 parseContext.popScope();
3130
3131 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003132}
3133
John Kessenich119f8f62016-06-05 15:44:07 -06003134// iteration_statement
3135// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3136// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3137// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3138//
3139// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003140bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3141{
John Kessenich119f8f62016-06-05 15:44:07 -06003142 TSourceLoc loc = token.loc;
3143 TIntermTyped* condition = nullptr;
3144
3145 EHlslTokenClass loop = peek();
3146 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3147
3148 // WHILE or DO or FOR
3149 advanceToken();
3150
3151 switch (loop) {
3152 case EHTokWhile:
3153 // so that something declared in the condition is scoped to the lifetime
3154 // of the while sub-statement
3155 parseContext.pushScope();
3156 parseContext.nestLooping();
3157
3158 // LEFT_PAREN condition RIGHT_PAREN
3159 if (! acceptParenExpression(condition))
3160 return false;
3161
3162 // statement
3163 if (! acceptScopedStatement(statement)) {
3164 expected("while sub-statement");
3165 return false;
3166 }
3167
3168 parseContext.unnestLooping();
3169 parseContext.popScope();
3170
3171 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3172
3173 return true;
3174
3175 case EHTokDo:
3176 parseContext.nestLooping();
3177
3178 if (! acceptTokenClass(EHTokLeftBrace))
3179 expected("{");
3180
3181 // statement
3182 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3183 expected("do sub-statement");
3184 return false;
3185 }
3186
3187 if (! acceptTokenClass(EHTokRightBrace))
3188 expected("}");
3189
3190 // WHILE
3191 if (! acceptTokenClass(EHTokWhile)) {
3192 expected("while");
3193 return false;
3194 }
3195
3196 // LEFT_PAREN condition RIGHT_PAREN
3197 TIntermTyped* condition;
3198 if (! acceptParenExpression(condition))
3199 return false;
3200
3201 if (! acceptTokenClass(EHTokSemicolon))
3202 expected(";");
3203
3204 parseContext.unnestLooping();
3205
3206 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3207
3208 return true;
3209
3210 case EHTokFor:
3211 {
3212 // LEFT_PAREN
3213 if (! acceptTokenClass(EHTokLeftParen))
3214 expected("(");
3215
3216 // so that something declared in the condition is scoped to the lifetime
3217 // of the for sub-statement
3218 parseContext.pushScope();
3219
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003220 // initializer
3221 TIntermNode* initNode = nullptr;
3222 if (! acceptControlDeclaration(initNode)) {
3223 TIntermTyped* initExpr = nullptr;
3224 acceptExpression(initExpr);
3225 initNode = initExpr;
3226 }
3227 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003228 if (! acceptTokenClass(EHTokSemicolon))
3229 expected(";");
3230
3231 parseContext.nestLooping();
3232
3233 // condition SEMI_COLON
3234 acceptExpression(condition);
3235 if (! acceptTokenClass(EHTokSemicolon))
3236 expected(";");
3237
3238 // iterator SEMI_COLON
3239 TIntermTyped* iterator = nullptr;
3240 acceptExpression(iterator);
3241 if (! acceptTokenClass(EHTokRightParen))
3242 expected(")");
3243
3244 // statement
3245 if (! acceptScopedStatement(statement)) {
3246 expected("for sub-statement");
3247 return false;
3248 }
3249
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003250 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003251
3252 parseContext.popScope();
3253 parseContext.unnestLooping();
3254
3255 return true;
3256 }
3257
3258 default:
3259 return false;
3260 }
John Kessenich21472ae2016-06-04 11:46:33 -06003261}
3262
3263// jump_statement
3264// : CONTINUE SEMICOLON
3265// | BREAK SEMICOLON
3266// | DISCARD SEMICOLON
3267// | RETURN SEMICOLON
3268// | RETURN expression SEMICOLON
3269//
3270bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3271{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003272 EHlslTokenClass jump = peek();
3273 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003274 case EHTokContinue:
3275 case EHTokBreak:
3276 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003277 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003278 advanceToken();
3279 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003280 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003281 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003282 return false;
3283 }
John Kessenich21472ae2016-06-04 11:46:33 -06003284
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003285 switch (jump) {
3286 case EHTokContinue:
3287 statement = intermediate.addBranch(EOpContinue, token.loc);
3288 break;
3289 case EHTokBreak:
3290 statement = intermediate.addBranch(EOpBreak, token.loc);
3291 break;
3292 case EHTokDiscard:
3293 statement = intermediate.addBranch(EOpKill, token.loc);
3294 break;
3295
3296 case EHTokReturn:
3297 {
3298 // expression
3299 TIntermTyped* node;
3300 if (acceptExpression(node)) {
3301 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003302 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003303 } else
3304 statement = intermediate.addBranch(EOpReturn, token.loc);
3305 break;
3306 }
3307
3308 default:
3309 assert(0);
3310 return false;
3311 }
3312
3313 // SEMICOLON
3314 if (! acceptTokenClass(EHTokSemicolon))
3315 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003316
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003317 return true;
3318}
John Kessenich21472ae2016-06-04 11:46:33 -06003319
John Kessenichd02dc5d2016-07-01 00:04:11 -06003320// case_label
3321// : CASE expression COLON
3322//
John Kessenich21472ae2016-06-04 11:46:33 -06003323bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3324{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003325 TSourceLoc loc = token.loc;
3326 if (! acceptTokenClass(EHTokCase))
3327 return false;
3328
3329 TIntermTyped* expression;
3330 if (! acceptExpression(expression)) {
3331 expected("case expression");
3332 return false;
3333 }
3334
3335 if (! acceptTokenClass(EHTokColon)) {
3336 expected(":");
3337 return false;
3338 }
3339
3340 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3341
3342 return true;
3343}
3344
3345// default_label
3346// : DEFAULT COLON
3347//
3348bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3349{
3350 TSourceLoc loc = token.loc;
3351 if (! acceptTokenClass(EHTokDefault))
3352 return false;
3353
3354 if (! acceptTokenClass(EHTokColon)) {
3355 expected(":");
3356 return false;
3357 }
3358
3359 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3360
3361 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003362}
3363
John Kessenich19b92ff2016-06-19 11:50:34 -06003364// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003365// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3366// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003367//
3368void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3369{
3370 arraySizes = nullptr;
3371
steve-lunarg7b211a32016-10-13 12:26:18 -06003372 // Early-out if there aren't any array dimensions
3373 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003374 return;
3375
steve-lunarg7b211a32016-10-13 12:26:18 -06003376 // 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 -06003377 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003378
3379 // Collect each array dimension.
3380 while (acceptTokenClass(EHTokLeftBracket)) {
3381 TSourceLoc loc = token.loc;
3382 TIntermTyped* sizeExpr = nullptr;
3383
John Kessenich057df292017-03-06 18:18:37 -07003384 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003385 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3386
3387 if (! acceptTokenClass(EHTokRightBracket)) {
3388 expected("]");
3389 return;
3390 }
3391
3392 if (hasArraySize) {
3393 TArraySize arraySize;
3394 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3395 arraySizes->addInnerSize(arraySize);
3396 } else {
3397 arraySizes->addInnerSize(0); // sized by initializers.
3398 }
steve-lunarg265c0612016-09-27 10:57:35 -06003399 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003400}
3401
John Kessenich630dd7d2016-06-12 23:52:12 -06003402// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003403// : COLON semantic // optional
3404// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3405// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003406// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003407// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003408//
John Kessenich854fe242017-03-02 14:30:59 -07003409// Return true if any tokens were accepted. That is,
3410// false can be returned on successfully recognizing nothing,
3411// not necessarily meaning bad syntax.
3412//
3413bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003414{
John Kessenich854fe242017-03-02 14:30:59 -07003415 bool found = false;
3416
John Kessenich630dd7d2016-06-12 23:52:12 -06003417 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003418 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003419 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003420 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003421 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003422 if (peekTokenClass(EHTokLayout))
3423 acceptLayoutQualifierList(qualifier);
3424 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003425 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003426 if (! acceptTokenClass(EHTokLeftParen)) {
3427 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003428 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003429 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003430 HlslToken locationToken;
3431 if (! acceptIdentifier(locationToken)) {
3432 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003433 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003434 }
3435 HlslToken componentToken;
3436 if (acceptTokenClass(EHTokDot)) {
3437 if (! acceptIdentifier(componentToken)) {
3438 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003439 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003440 }
3441 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003442 if (! acceptTokenClass(EHTokRightParen)) {
3443 expected(")");
3444 break;
3445 }
John Kessenich7735b942016-09-05 12:40:06 -06003446 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003447 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003448 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003449 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003450 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003451 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3452 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003453 if (! acceptTokenClass(EHTokLeftParen)) {
3454 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003455 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003456 }
John Kessenichb38f0712016-07-30 10:29:54 -06003457 HlslToken registerDesc; // for Type#
3458 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003459 if (! acceptIdentifier(registerDesc)) {
3460 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003461 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003462 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003463 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3464 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003465 // Then we didn't really see the registerDesc yet, it was
3466 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003467 profile = registerDesc;
3468 if (! acceptIdentifier(registerDesc)) {
3469 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003470 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003471 }
3472 }
John Kessenichb38f0712016-07-30 10:29:54 -06003473 int subComponent = 0;
3474 if (acceptTokenClass(EHTokLeftBracket)) {
3475 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3476 if (! peekTokenClass(EHTokIntConstant)) {
3477 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003478 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003479 }
3480 subComponent = token.i;
3481 advanceToken();
3482 if (! acceptTokenClass(EHTokRightBracket)) {
3483 expected("]");
3484 break;
3485 }
3486 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003487 // (COMMA SPACEN)opt
3488 HlslToken spaceDesc;
3489 if (acceptTokenClass(EHTokComma)) {
3490 if (! acceptIdentifier(spaceDesc)) {
3491 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003492 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003493 }
3494 }
3495 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003496 if (! acceptTokenClass(EHTokRightParen)) {
3497 expected(")");
3498 break;
3499 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003500 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003501 } else {
3502 // semantic, in idToken.string
John Kessenich6e1d50a2017-03-09 14:37:32 -07003503 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(*idToken.string));
John Kessenich630dd7d2016-06-12 23:52:12 -06003504 }
John Kessenich854fe242017-03-02 14:30:59 -07003505 } else if (peekTokenClass(EHTokLeftAngle)) {
3506 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003507 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003508 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003509 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003510
John Kessenich630dd7d2016-06-12 23:52:12 -06003511 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003512
3513 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003514}
3515
John Kesseniche01a9bc2016-03-12 20:11:22 -07003516} // end namespace glslang