blob: 01f9c122cbc4b137bed64bf3581aac0c9a6f9bc5 [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 Kessenichd5ed0b62016-07-04 17:32:45 -0600301 bool list = false;
John Kessenichd016be12016-03-13 11:24:20 -0600302
steve-lunarg1868b142016-10-20 13:07:10 -0600303 // attributes
304 TAttributeMap attributes;
305 acceptAttributes(attributes);
306
John Kessenich5e69ec62016-07-05 00:02:40 -0600307 // typedef
308 bool typedefDecl = acceptTokenClass(EHTokTypedef);
309
John Kesseniche82061d2016-09-27 14:38:57 -0600310 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600311
312 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600313 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
314 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
315 // HLSL shaders, this will have to be a master level switch
316 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700317 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700318 // if (acceptSamplerDeclarationDX9(declaredType))
319 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600320
321 // fully_specified_type
John Kesseniche82061d2016-09-27 14:38:57 -0600322 if (! acceptFullySpecifiedType(declaredType))
John Kessenich87142c72016-03-12 20:24:24 -0700323 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600324
John Kessenich87142c72016-03-12 20:24:24 -0700325 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600326 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700327 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600328 while (acceptIdentifier(idToken)) {
John Kessenich78388722017-03-08 18:53:51 -0700329 if (peekTokenClass(EHTokLeftParen)) {
330 // looks like function parameters
331 TString* fnName = idToken.string;
steve-lunargf1e0c872016-10-31 15:13:43 -0600332
John Kessenich78388722017-03-08 18:53:51 -0700333 // Potentially rename shader entry point function. No-op most of the time.
334 parseContext.renameShaderFunction(fnName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600335
John Kessenich78388722017-03-08 18:53:51 -0700336 // function_parameters
337 TFunction& function = *new TFunction(fnName, declaredType);
338 if (!acceptFunctionParameters(function)) {
339 expected("function parameter list");
340 return false;
341 }
342
John Kessenich630dd7d2016-06-12 23:52:12 -0600343 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -0600344 acceptPostDecls(function.getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600345
John Kessenichd5ed0b62016-07-04 17:32:45 -0600346 // compound_statement (function body definition) or just a prototype?
347 if (peekTokenClass(EHTokLeftBrace)) {
348 if (list)
349 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600350 if (typedefDecl)
351 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichca71d942017-03-07 20:44:09 -0700352 return acceptFunctionDefinition(function, nodeList, attributes);
John Kessenich5e69ec62016-07-05 00:02:40 -0600353 } else {
354 if (typedefDecl)
355 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich9e079532016-09-02 20:05:19 -0600356 parseContext.handleFunctionDeclarator(idToken.loc, function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600357 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600358 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600359 // A variable declaration. Fix the storage qualifier if it's a global.
360 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
361 declaredType.getQualifier().storage = EvqUniform;
362
John Kessenichecba76f2017-01-06 00:34:48 -0700363 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600364 // the number of types can expand when arrayness is different.
365 TType variableType;
366 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600367
John Kesseniche82061d2016-09-27 14:38:57 -0600368 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600369 TArraySizes* arraySizes = nullptr;
370 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600371
John Kesseniche82061d2016-09-27 14:38:57 -0600372 // Fix arrayness in the variableType
373 if (declaredType.isImplicitlySizedArray()) {
374 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
375 // of different sizes, for this case sharing the shallow copy of arrayness
376 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
377 variableType.newArraySizes(declaredType.getArraySizes());
378 }
379 if (arraySizes || variableType.isArray()) {
380 // In the most general case, arrayness is potentially coming both from the
381 // declared type and from the variable: "int[] a[];" or just one or the other.
382 // Merge it all to the variableType, so all arrayness is part of the variableType.
383 parseContext.arrayDimMerge(variableType, arraySizes);
384 }
385
LoopDawg4886f692016-06-29 10:58:58 -0600386 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600387 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600388 if (! acceptSamplerState())
389 return false;
390 }
391
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600393 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600394
395 // EQUAL assignment_expression
396 TIntermTyped* expressionNode = nullptr;
397 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600398 if (typedefDecl)
399 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600400 if (! acceptAssignmentExpression(expressionNode)) {
401 expected("initializer");
402 return false;
403 }
404 }
405
John Kessenich6dbc0a72016-09-27 19:13:05 -0600406 // TODO: things scoped within an annotation need their own name space;
407 // TODO: strings are not yet handled.
408 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
409 if (typedefDecl)
410 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
411 else if (variableType.getBasicType() == EbtBlock)
steve-lunargdd8287a2017-02-23 18:04:12 -0700412 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600413 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700414 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600415 // this isn't really an individual variable, but a member of the $Global buffer
416 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
417 } else {
418 // Declare the variable and add any initializer code to the AST.
419 // The top-level node is always made into an aggregate, as that's
420 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700421 initializers = intermediate.growAggregate(initializers,
422 parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
423 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600424 }
425 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600426 }
John Kessenich5f934b02016-03-13 17:58:25 -0600427 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600428
429 if (acceptTokenClass(EHTokComma)) {
430 list = true;
431 continue;
432 }
433 };
434
John Kessenichca71d942017-03-07 20:44:09 -0700435 // The top-level initializer node is a sequence.
436 if (initializers != nullptr)
437 initializers->setOperator(EOpSequence);
438
439 // Add the initializers' aggregate to the nodeList we were handed.
440 if (nodeList)
441 nodeList = intermediate.growAggregate(nodeList, initializers);
442 else
443 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700444
John Kessenich078d7f22016-03-14 10:02:11 -0600445 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600446 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700447 // This may have been a false detection of what appeared to be a declaration, but
448 // was actually an assignment such as "float = 4", where "float" is an identifier.
449 // We put the token back to let further parsing happen for cases where that may
450 // happen. This errors on the side of caution, and mostly triggers the error.
451
452 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
453 recedeToken();
454 else
455 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600456 return false;
457 }
John Kessenichecba76f2017-01-06 00:34:48 -0700458
John Kesseniche01a9bc2016-03-12 20:11:22 -0700459 return true;
460}
461
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600462// control_declaration
463// : fully_specified_type identifier EQUAL expression
464//
465bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
466{
467 node = nullptr;
468
469 // fully_specified_type
470 TType type;
471 if (! acceptFullySpecifiedType(type))
472 return false;
473
John Kessenich057df292017-03-06 18:18:37 -0700474 // filter out type casts
475 if (peekTokenClass(EHTokLeftParen)) {
476 recedeToken();
477 return false;
478 }
479
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600480 // identifier
481 HlslToken idToken;
482 if (! acceptIdentifier(idToken)) {
483 expected("identifier");
484 return false;
485 }
486
487 // EQUAL
488 TIntermTyped* expressionNode = nullptr;
489 if (! acceptTokenClass(EHTokAssign)) {
490 expected("=");
491 return false;
492 }
493
494 // expression
495 if (! acceptExpression(expressionNode)) {
496 expected("initializer");
497 return false;
498 }
499
John Kesseniche82061d2016-09-27 14:38:57 -0600500 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600501
502 return true;
503}
504
John Kessenich87142c72016-03-12 20:24:24 -0700505// fully_specified_type
506// : type_specifier
507// | type_qualifier type_specifier
508//
509bool HlslGrammar::acceptFullySpecifiedType(TType& type)
510{
511 // type_qualifier
512 TQualifier qualifier;
513 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600514 if (! acceptQualifier(qualifier))
515 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600516 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700517
518 // type_specifier
steve-lunarga64ed3e2016-12-18 17:51:14 -0700519 if (! acceptType(type)) {
520 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700521 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700522 // qualifier. Back it out, if we did.
523 if (qualifier.sample)
524 recedeToken();
525
John Kessenich87142c72016-03-12 20:24:24 -0700526 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700527 }
John Kessenich3d157c52016-07-25 16:05:33 -0600528 if (type.getBasicType() == EbtBlock) {
529 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600530 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600531 // further, it can create an anonymous instance of the block
532 if (peekTokenClass(EHTokSemicolon))
533 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600534 } else {
535 // Some qualifiers are set when parsing the type. Merge those with
536 // whatever comes from acceptQualifier.
537 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700538
steve-lunargbb0183f2016-10-04 16:58:14 -0600539 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600540 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700541
steve-lunarg5da1f032017-02-12 17:50:28 -0700542 if (type.getQualifier().storage == EvqVaryingOut ||
543 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700544 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700545 qualifier.readonly = type.getQualifier().readonly;
546 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700547
548 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600549 }
John Kessenich87142c72016-03-12 20:24:24 -0700550
551 return true;
552}
553
John Kessenich630dd7d2016-06-12 23:52:12 -0600554// type_qualifier
555// : qualifier qualifier ...
556//
557// Zero or more of these, so this can't return false.
558//
John Kessenichb9e39122016-08-17 10:22:08 -0600559bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700560{
John Kessenich630dd7d2016-06-12 23:52:12 -0600561 do {
562 switch (peek()) {
563 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600564 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600565 break;
566 case EHTokExtern:
567 // TODO: no meaning in glslang?
568 break;
569 case EHTokShared:
570 // TODO: hint
571 break;
572 case EHTokGroupShared:
573 qualifier.storage = EvqShared;
574 break;
575 case EHTokUniform:
576 qualifier.storage = EvqUniform;
577 break;
578 case EHTokConst:
579 qualifier.storage = EvqConst;
580 break;
581 case EHTokVolatile:
582 qualifier.volatil = true;
583 break;
584 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600585 qualifier.smooth = true;
586 break;
587 case EHTokCentroid:
588 qualifier.centroid = true;
589 break;
590 case EHTokNointerpolation:
591 qualifier.flat = true;
592 break;
593 case EHTokNoperspective:
594 qualifier.nopersp = true;
595 break;
596 case EHTokSample:
597 qualifier.sample = true;
598 break;
599 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600600 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600601 break;
602 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600603 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600604 break;
605 case EHTokPrecise:
606 qualifier.noContraction = true;
607 break;
LoopDawg9249c702016-07-12 20:44:32 -0600608 case EHTokIn:
609 qualifier.storage = EvqIn;
610 break;
611 case EHTokOut:
612 qualifier.storage = EvqOut;
613 break;
614 case EHTokInOut:
615 qualifier.storage = EvqInOut;
616 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600617 case EHTokLayout:
618 if (! acceptLayoutQualifierList(qualifier))
619 return false;
620 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700621 case EHTokGloballyCoherent:
622 qualifier.coherent = true;
623 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700624
625 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
626 // for output variables.
627 case EHTokPoint:
628 qualifier.storage = EvqIn;
629 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
630 return false;
631 break;
632 case EHTokLine:
633 qualifier.storage = EvqIn;
634 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
635 return false;
636 break;
637 case EHTokTriangle:
638 qualifier.storage = EvqIn;
639 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
640 return false;
641 break;
642 case EHTokLineAdj:
643 qualifier.storage = EvqIn;
644 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
645 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700646 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700647 case EHTokTriangleAdj:
648 qualifier.storage = EvqIn;
649 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
650 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700651 break;
652
John Kessenich630dd7d2016-06-12 23:52:12 -0600653 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600654 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600655 }
656 advanceToken();
657 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700658}
659
John Kessenichb9e39122016-08-17 10:22:08 -0600660// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600661// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600662//
663// layout_qualifier
664// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600665// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600666//
667// Zero or more of these, so this can't return false.
668//
669bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
670{
671 if (! acceptTokenClass(EHTokLayout))
672 return false;
673
674 // LEFT_PAREN
675 if (! acceptTokenClass(EHTokLeftParen))
676 return false;
677
678 do {
679 // identifier
680 HlslToken idToken;
681 if (! acceptIdentifier(idToken))
682 break;
683
684 // EQUAL expression
685 if (acceptTokenClass(EHTokAssign)) {
686 TIntermTyped* expr;
687 if (! acceptConditionalExpression(expr)) {
688 expected("expression");
689 return false;
690 }
691 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
692 } else
693 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
694
695 // COMMA
696 if (! acceptTokenClass(EHTokComma))
697 break;
698 } while (true);
699
700 // RIGHT_PAREN
701 if (! acceptTokenClass(EHTokRightParen)) {
702 expected(")");
703 return false;
704 }
705
706 return true;
707}
708
LoopDawg6daaa4f2016-06-23 19:13:48 -0600709// template_type
710// : FLOAT
711// | DOUBLE
712// | INT
713// | DWORD
714// | UINT
715// | BOOL
716//
steve-lunargf49cdf42016-11-17 15:04:20 -0700717bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600718{
719 switch (peek()) {
720 case EHTokFloat:
721 basicType = EbtFloat;
722 break;
723 case EHTokDouble:
724 basicType = EbtDouble;
725 break;
726 case EHTokInt:
727 case EHTokDword:
728 basicType = EbtInt;
729 break;
730 case EHTokUint:
731 basicType = EbtUint;
732 break;
733 case EHTokBool:
734 basicType = EbtBool;
735 break;
736 default:
737 return false;
738 }
739
740 advanceToken();
741
742 return true;
743}
744
745// vector_template_type
746// : VECTOR
747// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
748//
749bool HlslGrammar::acceptVectorTemplateType(TType& type)
750{
751 if (! acceptTokenClass(EHTokVector))
752 return false;
753
754 if (! acceptTokenClass(EHTokLeftAngle)) {
755 // in HLSL, 'vector' alone means float4.
756 new(&type) TType(EbtFloat, EvqTemporary, 4);
757 return true;
758 }
759
760 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700761 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600762 expected("scalar type");
763 return false;
764 }
765
766 // COMMA
767 if (! acceptTokenClass(EHTokComma)) {
768 expected(",");
769 return false;
770 }
771
772 // integer
773 if (! peekTokenClass(EHTokIntConstant)) {
774 expected("literal integer");
775 return false;
776 }
777
778 TIntermTyped* vecSize;
779 if (! acceptLiteral(vecSize))
780 return false;
781
782 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
783
784 new(&type) TType(basicType, EvqTemporary, vecSizeI);
785
786 if (vecSizeI == 1)
787 type.makeVector();
788
789 if (!acceptTokenClass(EHTokRightAngle)) {
790 expected("right angle bracket");
791 return false;
792 }
793
794 return true;
795}
796
797// matrix_template_type
798// : MATRIX
799// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
800//
801bool HlslGrammar::acceptMatrixTemplateType(TType& type)
802{
803 if (! acceptTokenClass(EHTokMatrix))
804 return false;
805
806 if (! acceptTokenClass(EHTokLeftAngle)) {
807 // in HLSL, 'matrix' alone means float4x4.
808 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
809 return true;
810 }
811
812 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700813 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600814 expected("scalar type");
815 return false;
816 }
817
818 // COMMA
819 if (! acceptTokenClass(EHTokComma)) {
820 expected(",");
821 return false;
822 }
823
824 // integer rows
825 if (! peekTokenClass(EHTokIntConstant)) {
826 expected("literal integer");
827 return false;
828 }
829
830 TIntermTyped* rows;
831 if (! acceptLiteral(rows))
832 return false;
833
834 // COMMA
835 if (! acceptTokenClass(EHTokComma)) {
836 expected(",");
837 return false;
838 }
John Kessenichecba76f2017-01-06 00:34:48 -0700839
LoopDawg6daaa4f2016-06-23 19:13:48 -0600840 // integer cols
841 if (! peekTokenClass(EHTokIntConstant)) {
842 expected("literal integer");
843 return false;
844 }
845
846 TIntermTyped* cols;
847 if (! acceptLiteral(cols))
848 return false;
849
850 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600851 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
852 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600853
854 if (!acceptTokenClass(EHTokRightAngle)) {
855 expected("right angle bracket");
856 return false;
857 }
858
859 return true;
860}
861
steve-lunargf49cdf42016-11-17 15:04:20 -0700862// layout_geometry
863// : LINESTREAM
864// | POINTSTREAM
865// | TRIANGLESTREAM
866//
867bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
868{
869 // read geometry type
870 const EHlslTokenClass geometryType = peek();
871
872 switch (geometryType) {
873 case EHTokPointStream: geometry = ElgPoints; break;
874 case EHTokLineStream: geometry = ElgLineStrip; break;
875 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
876 default:
877 return false; // not a layout geometry
878 }
879
880 advanceToken(); // consume the layout keyword
881 return true;
882}
883
steve-lunarg858c9282017-01-07 08:54:10 -0700884// tessellation_decl_type
885// : INPUTPATCH
886// | OUTPUTPATCH
887//
888bool HlslGrammar::acceptTessellationDeclType()
889{
890 // read geometry type
891 const EHlslTokenClass tessType = peek();
892
893 switch (tessType) {
894 case EHTokInputPatch: break;
895 case EHTokOutputPatch: break;
896 default:
897 return false; // not a tessellation decl
898 }
899
900 advanceToken(); // consume the keyword
901 return true;
902}
903
904// tessellation_patch_template_type
905// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
906//
907bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
908{
909 if (! acceptTessellationDeclType())
910 return false;
911
912 if (! acceptTokenClass(EHTokLeftAngle))
913 return false;
914
915 if (! acceptType(type)) {
916 expected("tessellation patch type");
917 return false;
918 }
919
920 if (! acceptTokenClass(EHTokComma))
921 return false;
922
923 // integer size
924 if (! peekTokenClass(EHTokIntConstant)) {
925 expected("literal integer");
926 return false;
927 }
928
929 TIntermTyped* size;
930 if (! acceptLiteral(size))
931 return false;
932
933 TArraySizes* arraySizes = new TArraySizes;
934 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
935 type.newArraySizes(*arraySizes);
936
937 if (! acceptTokenClass(EHTokRightAngle)) {
938 expected("right angle bracket");
939 return false;
940 }
941
942 return true;
943}
944
steve-lunargf49cdf42016-11-17 15:04:20 -0700945// stream_out_template_type
946// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
947//
948bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
949{
950 geometry = ElgNone;
951
952 if (! acceptOutputPrimitiveGeometry(geometry))
953 return false;
954
955 if (! acceptTokenClass(EHTokLeftAngle))
956 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700957
steve-lunargf49cdf42016-11-17 15:04:20 -0700958 if (! acceptType(type)) {
959 expected("stream output type");
960 return false;
961 }
962
963 type.getQualifier().storage = EvqVaryingOut;
964
965 if (! acceptTokenClass(EHTokRightAngle)) {
966 expected("right angle bracket");
967 return false;
968 }
969
970 return true;
971}
John Kessenichecba76f2017-01-06 00:34:48 -0700972
John Kessenicha1e2d492016-09-20 13:22:58 -0600973// annotations
974// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600975//
John Kessenicha1e2d492016-09-20 13:22:58 -0600976bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600977{
John Kessenicha1e2d492016-09-20 13:22:58 -0600978 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600979 return false;
980
John Kessenicha1e2d492016-09-20 13:22:58 -0600981 // note that we are nesting a name space
982 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600983
984 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
985 do {
986 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
987 while (acceptTokenClass(EHTokSemicolon))
988 ;
989
990 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -0600991 break;
John Kessenich86f71382016-09-19 20:23:18 -0600992
993 // declaration
John Kessenichca71d942017-03-07 20:44:09 -0700994 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -0600995 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -0600996 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -0600997 return false;
998 }
999 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001000
1001 parseContext.unnestAnnotations();
1002 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001003}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001004
LoopDawg4886f692016-06-29 10:58:58 -06001005// sampler_type
1006// : SAMPLER
1007// | SAMPLER1D
1008// | SAMPLER2D
1009// | SAMPLER3D
1010// | SAMPLERCUBE
1011// | SAMPLERSTATE
1012// | SAMPLERCOMPARISONSTATE
1013bool HlslGrammar::acceptSamplerType(TType& type)
1014{
1015 // read sampler type
1016 const EHlslTokenClass samplerType = peek();
1017
LoopDawga78b0292016-07-19 14:28:05 -06001018 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001019 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001020
LoopDawga78b0292016-07-19 14:28:05 -06001021 bool isShadow = false;
1022
LoopDawg4886f692016-06-29 10:58:58 -06001023 switch (samplerType) {
1024 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001025 case EHTokSampler1d: /*dim = Esd1D*/; break;
1026 case EHTokSampler2d: /*dim = Esd2D*/; break;
1027 case EHTokSampler3d: /*dim = Esd3D*/; break;
1028 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001029 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001030 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001031 default:
1032 return false; // not a sampler declaration
1033 }
1034
1035 advanceToken(); // consume the sampler type keyword
1036
1037 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001038
1039 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001040 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001041
1042 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1043
1044 return true;
1045}
1046
1047// texture_type
1048// | BUFFER
1049// | TEXTURE1D
1050// | TEXTURE1DARRAY
1051// | TEXTURE2D
1052// | TEXTURE2DARRAY
1053// | TEXTURE3D
1054// | TEXTURECUBE
1055// | TEXTURECUBEARRAY
1056// | TEXTURE2DMS
1057// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001058// | RWBUFFER
1059// | RWTEXTURE1D
1060// | RWTEXTURE1DARRAY
1061// | RWTEXTURE2D
1062// | RWTEXTURE2DARRAY
1063// | RWTEXTURE3D
1064
LoopDawg4886f692016-06-29 10:58:58 -06001065bool HlslGrammar::acceptTextureType(TType& type)
1066{
1067 const EHlslTokenClass textureType = peek();
1068
1069 TSamplerDim dim = EsdNone;
1070 bool array = false;
1071 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001072 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -06001073
1074 switch (textureType) {
1075 case EHTokBuffer: dim = EsdBuffer; break;
1076 case EHTokTexture1d: dim = Esd1D; break;
1077 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1078 case EHTokTexture2d: dim = Esd2D; break;
1079 case EHTokTexture2darray: dim = Esd2D; array = true; break;
John Kessenichecba76f2017-01-06 00:34:48 -07001080 case EHTokTexture3d: dim = Esd3D; break;
LoopDawg4886f692016-06-29 10:58:58 -06001081 case EHTokTextureCube: dim = EsdCube; break;
1082 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1083 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1084 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001085 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1086 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1087 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1088 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1089 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1090 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001091 default:
1092 return false; // not a texture declaration
1093 }
1094
1095 advanceToken(); // consume the texture object keyword
1096
1097 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001098
LoopDawg4886f692016-06-29 10:58:58 -06001099 TIntermTyped* msCount = nullptr;
1100
steve-lunargbb0183f2016-10-04 16:58:14 -06001101 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001102 if (acceptTokenClass(EHTokLeftAngle)) {
1103 if (! acceptType(txType)) {
1104 expected("scalar or vector type");
1105 return false;
1106 }
1107
1108 const TBasicType basicRetType = txType.getBasicType() ;
1109
1110 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1111 unimplemented("basic type in texture");
1112 return false;
1113 }
1114
steve-lunargd53f7172016-07-27 15:46:48 -06001115 // Buffers can handle small mats if they fit in 4 components
1116 if (dim == EsdBuffer && txType.isMatrix()) {
1117 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1118 expected("components < 4 in matrix buffer type");
1119 return false;
1120 }
1121
1122 // TODO: except we don't handle it yet...
1123 unimplemented("matrix type in buffer");
1124 return false;
1125 }
1126
LoopDawg4886f692016-06-29 10:58:58 -06001127 if (!txType.isScalar() && !txType.isVector()) {
1128 expected("scalar or vector type");
1129 return false;
1130 }
1131
LoopDawg4886f692016-06-29 10:58:58 -06001132 if (ms && acceptTokenClass(EHTokComma)) {
1133 // read sample count for multisample types, if given
1134 if (! peekTokenClass(EHTokIntConstant)) {
1135 expected("multisample count");
1136 return false;
1137 }
1138
1139 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1140 return false;
1141 }
1142
1143 if (! acceptTokenClass(EHTokRightAngle)) {
1144 expected("right angle bracket");
1145 return false;
1146 }
1147 } else if (ms) {
1148 expected("texture type for multisample");
1149 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001150 } else if (image) {
1151 expected("type for RWTexture/RWBuffer");
1152 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001153 }
1154
1155 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001156 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001157
1158 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001159 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001160
steve-lunarg4f2da272016-10-10 15:24:57 -06001161 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1162 if (image || dim == EsdBuffer)
1163 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001164
1165 // Non-image Buffers are combined
1166 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001167 sampler.set(txType.getBasicType(), dim, array);
1168 } else {
1169 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001170 if (image) {
1171 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1172 } else {
1173 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1174 }
steve-lunargd53f7172016-07-27 15:46:48 -06001175 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001176
1177 // Remember the declared vector size.
1178 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001179
LoopDawg4886f692016-06-29 10:58:58 -06001180 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001181 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001182
1183 return true;
1184}
1185
John Kessenich87142c72016-03-12 20:24:24 -07001186// If token is for a type, update 'type' with the type information,
1187// and return true and advance.
1188// Otherwise, return false, and don't advance
1189bool HlslGrammar::acceptType(TType& type)
1190{
steve-lunarg3226b082016-10-26 19:18:55 -06001191 // Basic types for min* types, broken out here in case of future
1192 // changes, e.g, to use native halfs.
1193 static const TBasicType min16float_bt = EbtFloat;
1194 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001195 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001196 static const TBasicType min16int_bt = EbtInt;
1197 static const TBasicType min12int_bt = EbtInt;
1198 static const TBasicType min16uint_bt = EbtUint;
1199
John Kessenich9c86c6a2016-05-03 22:49:24 -06001200 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001201 case EHTokVector:
1202 return acceptVectorTemplateType(type);
1203 break;
1204
1205 case EHTokMatrix:
1206 return acceptMatrixTemplateType(type);
1207 break;
1208
steve-lunargf49cdf42016-11-17 15:04:20 -07001209 case EHTokPointStream: // fall through
1210 case EHTokLineStream: // ...
1211 case EHTokTriangleStream: // ...
1212 {
1213 TLayoutGeometry geometry;
1214 if (! acceptStreamOutTemplateType(type, geometry))
1215 return false;
1216
1217 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1218 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001219
steve-lunargf49cdf42016-11-17 15:04:20 -07001220 return true;
1221 }
1222
steve-lunarg858c9282017-01-07 08:54:10 -07001223 case EHTokInputPatch: // fall through
1224 case EHTokOutputPatch: // ...
1225 {
1226 if (! acceptTessellationPatchTemplateType(type))
1227 return false;
1228
1229 return true;
1230 }
1231
LoopDawg4886f692016-06-29 10:58:58 -06001232 case EHTokSampler: // fall through
1233 case EHTokSampler1d: // ...
1234 case EHTokSampler2d: // ...
1235 case EHTokSampler3d: // ...
1236 case EHTokSamplerCube: // ...
1237 case EHTokSamplerState: // ...
1238 case EHTokSamplerComparisonState: // ...
1239 return acceptSamplerType(type);
1240 break;
1241
1242 case EHTokBuffer: // fall through
1243 case EHTokTexture1d: // ...
1244 case EHTokTexture1darray: // ...
1245 case EHTokTexture2d: // ...
1246 case EHTokTexture2darray: // ...
1247 case EHTokTexture3d: // ...
1248 case EHTokTextureCube: // ...
1249 case EHTokTextureCubearray: // ...
1250 case EHTokTexture2DMS: // ...
1251 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001252 case EHTokRWTexture1d: // ...
1253 case EHTokRWTexture1darray: // ...
1254 case EHTokRWTexture2d: // ...
1255 case EHTokRWTexture2darray: // ...
1256 case EHTokRWTexture3d: // ...
1257 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001258 return acceptTextureType(type);
1259 break;
1260
steve-lunarg5da1f032017-02-12 17:50:28 -07001261 case EHTokAppendStructuredBuffer:
1262 case EHTokByteAddressBuffer:
1263 case EHTokConsumeStructuredBuffer:
1264 case EHTokRWByteAddressBuffer:
1265 case EHTokRWStructuredBuffer:
1266 case EHTokStructuredBuffer:
1267 return acceptStructBufferType(type);
1268 break;
1269
John Kessenich27ffb292017-03-03 17:01:01 -07001270 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001271 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001272 case EHTokCBuffer:
1273 case EHTokTBuffer:
John Kesseniche6e74942016-06-11 16:43:14 -06001274 return acceptStruct(type);
John Kesseniche6e74942016-06-11 16:43:14 -06001275
1276 case EHTokIdentifier:
1277 // An identifier could be for a user-defined type.
1278 // Note we cache the symbol table lookup, to save for a later rule
1279 // when this is not a type.
John Kessenich854fe242017-03-02 14:30:59 -07001280 token.symbol = parseContext.lookupUserType(*token.string, type);
1281 if (token.symbol != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001282 advanceToken();
1283 return true;
1284 } else
1285 return false;
1286
John Kessenich71351de2016-06-08 12:50:56 -06001287 case EHTokVoid:
1288 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001289 break;
John Kessenich71351de2016-06-08 12:50:56 -06001290
John Kessenicha1e2d492016-09-20 13:22:58 -06001291 case EHTokString:
1292 new(&type) TType(EbtString);
1293 break;
1294
John Kessenich87142c72016-03-12 20:24:24 -07001295 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001296 new(&type) TType(EbtFloat);
1297 break;
John Kessenich87142c72016-03-12 20:24:24 -07001298 case EHTokFloat1:
1299 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001300 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001301 break;
John Kessenich87142c72016-03-12 20:24:24 -07001302 case EHTokFloat2:
1303 new(&type) TType(EbtFloat, EvqTemporary, 2);
1304 break;
1305 case EHTokFloat3:
1306 new(&type) TType(EbtFloat, EvqTemporary, 3);
1307 break;
1308 case EHTokFloat4:
1309 new(&type) TType(EbtFloat, EvqTemporary, 4);
1310 break;
1311
John Kessenich71351de2016-06-08 12:50:56 -06001312 case EHTokDouble:
1313 new(&type) TType(EbtDouble);
1314 break;
1315 case EHTokDouble1:
1316 new(&type) TType(EbtDouble);
1317 type.makeVector();
1318 break;
1319 case EHTokDouble2:
1320 new(&type) TType(EbtDouble, EvqTemporary, 2);
1321 break;
1322 case EHTokDouble3:
1323 new(&type) TType(EbtDouble, EvqTemporary, 3);
1324 break;
1325 case EHTokDouble4:
1326 new(&type) TType(EbtDouble, EvqTemporary, 4);
1327 break;
1328
1329 case EHTokInt:
1330 case EHTokDword:
1331 new(&type) TType(EbtInt);
1332 break;
1333 case EHTokInt1:
1334 new(&type) TType(EbtInt);
1335 type.makeVector();
1336 break;
John Kessenich87142c72016-03-12 20:24:24 -07001337 case EHTokInt2:
1338 new(&type) TType(EbtInt, EvqTemporary, 2);
1339 break;
1340 case EHTokInt3:
1341 new(&type) TType(EbtInt, EvqTemporary, 3);
1342 break;
1343 case EHTokInt4:
1344 new(&type) TType(EbtInt, EvqTemporary, 4);
1345 break;
1346
John Kessenich71351de2016-06-08 12:50:56 -06001347 case EHTokUint:
1348 new(&type) TType(EbtUint);
1349 break;
1350 case EHTokUint1:
1351 new(&type) TType(EbtUint);
1352 type.makeVector();
1353 break;
1354 case EHTokUint2:
1355 new(&type) TType(EbtUint, EvqTemporary, 2);
1356 break;
1357 case EHTokUint3:
1358 new(&type) TType(EbtUint, EvqTemporary, 3);
1359 break;
1360 case EHTokUint4:
1361 new(&type) TType(EbtUint, EvqTemporary, 4);
1362 break;
1363
1364 case EHTokBool:
1365 new(&type) TType(EbtBool);
1366 break;
1367 case EHTokBool1:
1368 new(&type) TType(EbtBool);
1369 type.makeVector();
1370 break;
John Kessenich87142c72016-03-12 20:24:24 -07001371 case EHTokBool2:
1372 new(&type) TType(EbtBool, EvqTemporary, 2);
1373 break;
1374 case EHTokBool3:
1375 new(&type) TType(EbtBool, EvqTemporary, 3);
1376 break;
1377 case EHTokBool4:
1378 new(&type) TType(EbtBool, EvqTemporary, 4);
1379 break;
1380
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001381 case EHTokHalf:
1382 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1383 break;
1384 case EHTokHalf1:
1385 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1386 type.makeVector();
1387 break;
1388 case EHTokHalf2:
1389 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1390 break;
1391 case EHTokHalf3:
1392 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1393 break;
1394 case EHTokHalf4:
1395 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1396 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001397
steve-lunarg3226b082016-10-26 19:18:55 -06001398 case EHTokMin16float:
1399 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1400 break;
1401 case EHTokMin16float1:
1402 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1403 type.makeVector();
1404 break;
1405 case EHTokMin16float2:
1406 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1407 break;
1408 case EHTokMin16float3:
1409 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1410 break;
1411 case EHTokMin16float4:
1412 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1413 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001414
steve-lunarg3226b082016-10-26 19:18:55 -06001415 case EHTokMin10float:
1416 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1417 break;
1418 case EHTokMin10float1:
1419 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1420 type.makeVector();
1421 break;
1422 case EHTokMin10float2:
1423 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1424 break;
1425 case EHTokMin10float3:
1426 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1427 break;
1428 case EHTokMin10float4:
1429 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1430 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001431
steve-lunarg3226b082016-10-26 19:18:55 -06001432 case EHTokMin16int:
1433 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1434 break;
1435 case EHTokMin16int1:
1436 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1437 type.makeVector();
1438 break;
1439 case EHTokMin16int2:
1440 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1441 break;
1442 case EHTokMin16int3:
1443 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1444 break;
1445 case EHTokMin16int4:
1446 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1447 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001448
steve-lunarg3226b082016-10-26 19:18:55 -06001449 case EHTokMin12int:
1450 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1451 break;
1452 case EHTokMin12int1:
1453 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1454 type.makeVector();
1455 break;
1456 case EHTokMin12int2:
1457 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1458 break;
1459 case EHTokMin12int3:
1460 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1461 break;
1462 case EHTokMin12int4:
1463 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1464 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001465
steve-lunarg3226b082016-10-26 19:18:55 -06001466 case EHTokMin16uint:
1467 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1468 break;
1469 case EHTokMin16uint1:
1470 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1471 type.makeVector();
1472 break;
1473 case EHTokMin16uint2:
1474 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1475 break;
1476 case EHTokMin16uint3:
1477 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1478 break;
1479 case EHTokMin16uint4:
1480 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1481 break;
1482
John Kessenich0133c122016-05-20 12:17:26 -06001483 case EHTokInt1x1:
1484 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1485 break;
1486 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001487 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001488 break;
1489 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001490 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001491 break;
1492 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001493 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001494 break;
1495 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001496 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001497 break;
1498 case EHTokInt2x2:
1499 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1500 break;
1501 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001502 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001503 break;
1504 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001505 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001506 break;
1507 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001508 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001509 break;
1510 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001511 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001512 break;
1513 case EHTokInt3x3:
1514 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1515 break;
1516 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001517 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001518 break;
1519 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001520 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001521 break;
1522 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001523 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001524 break;
1525 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001526 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001527 break;
1528 case EHTokInt4x4:
1529 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1530 break;
1531
John Kessenich71351de2016-06-08 12:50:56 -06001532 case EHTokUint1x1:
1533 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1534 break;
1535 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001536 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001537 break;
1538 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001539 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001540 break;
1541 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001542 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001543 break;
1544 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001545 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001546 break;
1547 case EHTokUint2x2:
1548 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1549 break;
1550 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001551 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001552 break;
1553 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001554 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001555 break;
1556 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001557 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001558 break;
1559 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001560 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001561 break;
1562 case EHTokUint3x3:
1563 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1564 break;
1565 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001566 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001567 break;
1568 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001569 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001570 break;
1571 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001572 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001573 break;
1574 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001575 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001576 break;
1577 case EHTokUint4x4:
1578 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1579 break;
1580
1581 case EHTokBool1x1:
1582 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1583 break;
1584 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001585 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001586 break;
1587 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001588 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001589 break;
1590 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001591 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001592 break;
1593 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001594 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001595 break;
1596 case EHTokBool2x2:
1597 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1598 break;
1599 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001600 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001601 break;
1602 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001603 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001604 break;
1605 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001606 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001607 break;
1608 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001609 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001610 break;
1611 case EHTokBool3x3:
1612 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1613 break;
1614 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001615 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001616 break;
1617 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001618 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001619 break;
1620 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001621 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001622 break;
1623 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001624 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001625 break;
1626 case EHTokBool4x4:
1627 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1628 break;
1629
John Kessenich0133c122016-05-20 12:17:26 -06001630 case EHTokFloat1x1:
1631 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1632 break;
1633 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001634 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001635 break;
1636 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001637 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001638 break;
1639 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001640 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001641 break;
1642 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001643 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001644 break;
John Kessenich87142c72016-03-12 20:24:24 -07001645 case EHTokFloat2x2:
1646 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1647 break;
1648 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001649 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001650 break;
1651 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001652 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001653 break;
John Kessenich0133c122016-05-20 12:17:26 -06001654 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001655 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001656 break;
John Kessenich87142c72016-03-12 20:24:24 -07001657 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001658 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001659 break;
1660 case EHTokFloat3x3:
1661 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1662 break;
1663 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001664 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001665 break;
John Kessenich0133c122016-05-20 12:17:26 -06001666 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001667 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001668 break;
John Kessenich87142c72016-03-12 20:24:24 -07001669 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001670 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001671 break;
1672 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001673 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001674 break;
1675 case EHTokFloat4x4:
1676 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1677 break;
1678
John Kessenich0133c122016-05-20 12:17:26 -06001679 case EHTokDouble1x1:
1680 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1681 break;
1682 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001683 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001684 break;
1685 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001686 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001687 break;
1688 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001689 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001690 break;
1691 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001692 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001693 break;
1694 case EHTokDouble2x2:
1695 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1696 break;
1697 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001698 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001699 break;
1700 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001701 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001702 break;
1703 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001704 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001705 break;
1706 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001707 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001708 break;
1709 case EHTokDouble3x3:
1710 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1711 break;
1712 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001713 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001714 break;
1715 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001716 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001717 break;
1718 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001719 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001720 break;
1721 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001722 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001723 break;
1724 case EHTokDouble4x4:
1725 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1726 break;
1727
John Kessenich87142c72016-03-12 20:24:24 -07001728 default:
1729 return false;
1730 }
1731
1732 advanceToken();
1733
1734 return true;
1735}
1736
John Kesseniche6e74942016-06-11 16:43:14 -06001737// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001738// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1739// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001740// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001741//
1742// struct_type
1743// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001744// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001745// | CBUFFER
1746// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001747//
1748bool HlslGrammar::acceptStruct(TType& type)
1749{
John Kessenichb804de62016-09-05 12:19:18 -06001750 // This storage qualifier will tell us whether it's an AST
1751 // block type or just a generic structure type.
1752 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001753
1754 // CBUFFER
1755 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001756 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001757 // TBUFFER
1758 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001759 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001760 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001761 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001762 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001763 return false;
1764
1765 // IDENTIFIER
1766 TString structName = "";
1767 if (peekTokenClass(EHTokIdentifier)) {
1768 structName = *token.string;
1769 advanceToken();
1770 }
1771
John Kessenich3d157c52016-07-25 16:05:33 -06001772 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001773 TQualifier postDeclQualifier;
1774 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001775 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001776
John Kesseniche6e74942016-06-11 16:43:14 -06001777 // LEFT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001778 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001779 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001780 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1781 // struct_type IDENTIFIER
1782 return true;
1783 } else {
1784 expected("{");
1785 return false;
1786 }
John Kesseniche6e74942016-06-11 16:43:14 -06001787 }
1788
1789 // struct_declaration_list
1790 TTypeList* typeList;
1791 if (! acceptStructDeclarationList(typeList)) {
1792 expected("struct member declarations");
1793 return false;
1794 }
1795
1796 // RIGHT_BRACE
1797 if (! acceptTokenClass(EHTokRightBrace)) {
1798 expected("}");
1799 return false;
1800 }
1801
1802 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001803 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001804 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001805 else {
John Kessenich7735b942016-09-05 12:40:06 -06001806 postDeclQualifier.storage = storageQualifier;
1807 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001808 }
John Kesseniche6e74942016-06-11 16:43:14 -06001809
John Kessenich727b3742017-02-03 17:57:55 -07001810 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001811
1812 return true;
1813}
1814
steve-lunarg5da1f032017-02-12 17:50:28 -07001815// struct_buffer
1816// : APPENDSTRUCTUREDBUFFER
1817// | BYTEADDRESSBUFFER
1818// | CONSUMESTRUCTUREDBUFFER
1819// | RWBYTEADDRESSBUFFER
1820// | RWSTRUCTUREDBUFFER
1821// | STRUCTUREDBUFFER
1822bool HlslGrammar::acceptStructBufferType(TType& type)
1823{
1824 const EHlslTokenClass structBuffType = peek();
1825
1826 // TODO: globallycoherent
1827 bool hasTemplateType = true;
1828 bool readonly = false;
1829
1830 TStorageQualifier storage = EvqBuffer;
1831
1832 switch (structBuffType) {
1833 case EHTokAppendStructuredBuffer:
1834 unimplemented("AppendStructuredBuffer");
1835 return false;
1836 case EHTokByteAddressBuffer:
1837 hasTemplateType = false;
1838 readonly = true;
1839 break;
1840 case EHTokConsumeStructuredBuffer:
1841 unimplemented("ConsumeStructuredBuffer");
1842 return false;
1843 case EHTokRWByteAddressBuffer:
1844 hasTemplateType = false;
1845 break;
1846 case EHTokRWStructuredBuffer:
1847 break;
1848 case EHTokStructuredBuffer:
1849 readonly = true;
1850 break;
1851 default:
1852 return false; // not a structure buffer type
1853 }
1854
1855 advanceToken(); // consume the structure keyword
1856
1857 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1858 TType* templateType = new TType;
1859
1860 if (hasTemplateType) {
1861 if (! acceptTokenClass(EHTokLeftAngle)) {
1862 expected("left angle bracket");
1863 return false;
1864 }
1865
1866 if (! acceptType(*templateType)) {
1867 expected("type");
1868 return false;
1869 }
1870 if (! acceptTokenClass(EHTokRightAngle)) {
1871 expected("right angle bracket");
1872 return false;
1873 }
1874 } else {
1875 // byte address buffers have no explicit type.
1876 TType uintType(EbtUint, storage);
1877 templateType->shallowCopy(uintType);
1878 }
1879
1880 // Create an unsized array out of that type.
1881 // TODO: does this work if it's already an array type?
1882 TArraySizes unsizedArray;
1883 unsizedArray.addInnerSize(UnsizedArraySize);
1884 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07001885 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07001886
1887 // field name is canonical for all structbuffers
1888 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07001889
1890 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07001891
steve-lunarg5da1f032017-02-12 17:50:28 -07001892 TTypeList* blockStruct = new TTypeList;
1893 TTypeLoc member = { templateType, token.loc };
1894 blockStruct->push_back(member);
1895
steve-lunargdd8287a2017-02-23 18:04:12 -07001896 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07001897 TType blockType(blockStruct, "", templateType->getQualifier());
1898
steve-lunargdd8287a2017-02-23 18:04:12 -07001899 blockType.getQualifier().storage = storage;
1900 blockType.getQualifier().readonly = readonly;
1901
1902 // We may have created an equivalent type before, in which case we should use its
1903 // deep structure.
1904 parseContext.shareStructBufferType(blockType);
1905
steve-lunarg5da1f032017-02-12 17:50:28 -07001906 type.shallowCopy(blockType);
1907
1908 return true;
1909}
1910
John Kesseniche6e74942016-06-11 16:43:14 -06001911// struct_declaration_list
1912// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1913//
1914// struct_declaration
1915// : fully_specified_type struct_declarator COMMA struct_declarator ...
1916//
1917// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001918// : IDENTIFIER post_decls
1919// | IDENTIFIER array_specifier post_decls
John Kesseniche6e74942016-06-11 16:43:14 -06001920//
1921bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
1922{
1923 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001924 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001925
1926 do {
1927 // success on seeing the RIGHT_BRACE coming up
1928 if (peekTokenClass(EHTokRightBrace))
1929 return true;
1930
1931 // struct_declaration
1932
1933 // fully_specified_type
1934 TType memberType;
1935 if (! acceptFullySpecifiedType(memberType)) {
1936 expected("member type");
1937 return false;
1938 }
1939
1940 // struct_declarator COMMA struct_declarator ...
1941 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001942 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001943 expected("member name");
1944 return false;
1945 }
1946
1947 // add it to the list of members
1948 TTypeLoc member = { new TType(EbtVoid), token.loc };
1949 member.type->shallowCopy(memberType);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001950 member.type->setFieldName(*idToken.string);
John Kesseniche6e74942016-06-11 16:43:14 -06001951 typeList->push_back(member);
1952
John Kesseniche6e74942016-06-11 16:43:14 -06001953 // array_specifier
John Kessenich19b92ff2016-06-19 11:50:34 -06001954 TArraySizes* arraySizes = nullptr;
1955 acceptArraySpecifier(arraySizes);
1956 if (arraySizes)
1957 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001958
John Kessenich7735b942016-09-05 12:40:06 -06001959 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06001960
John Kessenich18adbdb2017-02-02 15:16:20 -07001961 // EQUAL assignment_expression
1962 if (acceptTokenClass(EHTokAssign)) {
1963 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
1964 TIntermTyped* expressionNode = nullptr;
1965 if (! acceptAssignmentExpression(expressionNode)) {
1966 expected("initializer");
1967 return false;
1968 }
1969 }
1970
John Kesseniche6e74942016-06-11 16:43:14 -06001971 // success on seeing the SEMICOLON coming up
1972 if (peekTokenClass(EHTokSemicolon))
1973 break;
1974
1975 // COMMA
1976 if (! acceptTokenClass(EHTokComma)) {
1977 expected(",");
1978 return false;
1979 }
1980
1981 } while (true);
1982
1983 // SEMI_COLON
1984 if (! acceptTokenClass(EHTokSemicolon)) {
1985 expected(";");
1986 return false;
1987 }
1988
1989 } while (true);
1990}
1991
John Kessenich5f934b02016-03-13 17:58:25 -06001992// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06001993// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06001994// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001995//
1996bool HlslGrammar::acceptFunctionParameters(TFunction& function)
1997{
John Kessenich078d7f22016-03-14 10:02:11 -06001998 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001999 if (! acceptTokenClass(EHTokLeftParen))
2000 return false;
2001
John Kessenich71351de2016-06-08 12:50:56 -06002002 // VOID RIGHT_PAREN
2003 if (! acceptTokenClass(EHTokVoid)) {
2004 do {
2005 // parameter_declaration
2006 if (! acceptParameterDeclaration(function))
2007 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002008
John Kessenich71351de2016-06-08 12:50:56 -06002009 // COMMA
2010 if (! acceptTokenClass(EHTokComma))
2011 break;
2012 } while (true);
2013 }
John Kessenich5f934b02016-03-13 17:58:25 -06002014
John Kessenich078d7f22016-03-14 10:02:11 -06002015 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002016 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002017 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002018 return false;
2019 }
2020
2021 return true;
2022}
2023
steve-lunarg26d31452016-12-23 18:56:57 -07002024// default_parameter_declaration
2025// : EQUAL conditional_expression
2026// : EQUAL initializer
2027bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2028{
2029 node = nullptr;
2030
2031 // Valid not to have a default_parameter_declaration
2032 if (!acceptTokenClass(EHTokAssign))
2033 return true;
2034
2035 if (!acceptConditionalExpression(node)) {
2036 if (!acceptInitializer(node))
2037 return false;
2038
2039 // For initializer lists, we have to const-fold into a constructor for the type, so build
2040 // that.
2041 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2042 if (constructor == nullptr) // cannot construct
2043 return false;
2044
2045 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002046 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002047 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002048
steve-lunarg26d31452016-12-23 18:56:57 -07002049 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2050 }
2051
2052 // If this is simply a constant, we can use it directly.
2053 if (node->getAsConstantUnion())
2054 return true;
2055
2056 // Otherwise, it has to be const-foldable.
2057 TIntermTyped* origNode = node;
2058
2059 node = intermediate.fold(node->getAsAggregate());
2060
2061 if (node != nullptr && origNode != node)
2062 return true;
2063
2064 parseContext.error(token.loc, "invalid default parameter value", "", "");
2065
2066 return false;
2067}
2068
John Kessenich5f934b02016-03-13 17:58:25 -06002069// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002070// : fully_specified_type post_decls [ = default_parameter_declaration ]
2071// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002072//
2073bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2074{
2075 // fully_specified_type
2076 TType* type = new TType;
2077 if (! acceptFullySpecifiedType(*type))
2078 return false;
2079
2080 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002081 HlslToken idToken;
2082 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002083
John Kessenich19b92ff2016-06-19 11:50:34 -06002084 // array_specifier
2085 TArraySizes* arraySizes = nullptr;
2086 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002087 if (arraySizes) {
2088 if (arraySizes->isImplicit()) {
2089 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2090 return false;
2091 }
2092
John Kessenich19b92ff2016-06-19 11:50:34 -06002093 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002094 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002095
2096 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002097 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002098
steve-lunarg26d31452016-12-23 18:56:57 -07002099 TIntermTyped* defaultValue;
2100 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2101 return false;
2102
John Kessenich5aa59e22016-06-17 15:50:47 -06002103 parseContext.paramFix(*type);
2104
steve-lunarg26d31452016-12-23 18:56:57 -07002105 // If any prior parameters have default values, all the parameters after that must as well.
2106 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2107 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2108 return false;
2109 }
2110
2111 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002112 function.addParameter(param);
2113
2114 return true;
2115}
2116
2117// Do the work to create the function definition in addition to
2118// parsing the body (compound_statement).
John Kessenichca71d942017-03-07 20:44:09 -07002119bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& nodeList, const TAttributeMap& attributes)
John Kessenich5f934b02016-03-13 17:58:25 -06002120{
John Kessenicha3051662016-09-02 19:13:36 -06002121 TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
John Kessenich1a4b7752016-09-02 19:05:24 -06002122 TSourceLoc loc = token.loc;
John Kessenich5f934b02016-03-13 17:58:25 -06002123
John Kessenichca71d942017-03-07 20:44:09 -07002124 // we might get back and entry-point
2125 TIntermNode* entryPointNode = nullptr;
2126
John Kessenich077e0522016-06-09 02:02:17 -06002127 // This does a pushScope()
John Kessenichca71d942017-03-07 20:44:09 -07002128 TIntermNode* functionNode = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes,
2129 entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002130
2131 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002132 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002133 if (! acceptCompoundStatement(functionBody))
2134 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002135
John Kessenichca71d942017-03-07 20:44:09 -07002136 parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, functionNode);
2137
2138 // Hook up the 1 or 2 function definitions.
2139 nodeList = intermediate.growAggregate(nodeList, functionNode);
2140 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002141
2142 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002143}
2144
John Kessenich0d2b6de2016-06-05 11:23:11 -06002145// Accept an expression with parenthesis around it, where
2146// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002147// syntactically required ones like in "if ( expression )".
2148//
2149// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002150//
2151// Note this one is not set up to be speculative; as it gives
2152// errors if not found.
2153//
2154bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2155{
2156 // LEFT_PAREN
2157 if (! acceptTokenClass(EHTokLeftParen))
2158 expected("(");
2159
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002160 bool decl = false;
2161 TIntermNode* declNode = nullptr;
2162 decl = acceptControlDeclaration(declNode);
2163 if (decl) {
2164 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2165 expected("initialized declaration");
2166 return false;
2167 } else
2168 expression = declNode->getAsTyped();
2169 } else {
2170 // no declaration
2171 if (! acceptExpression(expression)) {
2172 expected("expression");
2173 return false;
2174 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002175 }
2176
2177 // RIGHT_PAREN
2178 if (! acceptTokenClass(EHTokRightParen))
2179 expected(")");
2180
2181 return true;
2182}
2183
John Kessenich34fb0362016-05-03 23:17:20 -06002184// The top-level full expression recognizer.
2185//
John Kessenich87142c72016-03-12 20:24:24 -07002186// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002187// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002188//
2189bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2190{
LoopDawgef764a22016-06-03 09:17:51 -06002191 node = nullptr;
2192
John Kessenich34fb0362016-05-03 23:17:20 -06002193 // assignment_expression
2194 if (! acceptAssignmentExpression(node))
2195 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002196
John Kessenich34fb0362016-05-03 23:17:20 -06002197 if (! peekTokenClass(EHTokComma))
2198 return true;
2199
2200 do {
2201 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002202 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002203 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002204
John Kessenich34fb0362016-05-03 23:17:20 -06002205 // ... assignment_expression
2206 TIntermTyped* rightNode = nullptr;
2207 if (! acceptAssignmentExpression(rightNode)) {
2208 expected("assignment expression");
2209 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002210 }
2211
John Kessenich34fb0362016-05-03 23:17:20 -06002212 node = intermediate.addComma(node, rightNode, loc);
2213
2214 if (! peekTokenClass(EHTokComma))
2215 return true;
2216 } while (true);
2217}
2218
John Kessenich07354242016-07-01 19:58:06 -06002219// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002220// : LEFT_BRACE RIGHT_BRACE
2221// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002222//
2223// initializer_list
2224// : assignment_expression COMMA assignment_expression COMMA ...
2225//
2226bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2227{
2228 // LEFT_BRACE
2229 if (! acceptTokenClass(EHTokLeftBrace))
2230 return false;
2231
John Kessenich98ad4852016-11-27 17:39:07 -07002232 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002233 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002234 if (acceptTokenClass(EHTokRightBrace)) {
2235 // a zero-length initializer list
2236 node = intermediate.makeAggregate(loc);
2237 return true;
2238 }
2239
2240 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002241 node = nullptr;
2242 do {
2243 // assignment_expression
2244 TIntermTyped* expr;
2245 if (! acceptAssignmentExpression(expr)) {
2246 expected("assignment expression in initializer list");
2247 return false;
2248 }
2249 node = intermediate.growAggregate(node, expr, loc);
2250
2251 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002252 if (acceptTokenClass(EHTokComma)) {
2253 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2254 return true;
John Kessenich07354242016-07-01 19:58:06 -06002255 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002256 }
John Kessenich07354242016-07-01 19:58:06 -06002257
2258 // RIGHT_BRACE
2259 if (acceptTokenClass(EHTokRightBrace))
2260 return true;
2261
2262 expected(", or }");
2263 return false;
2264 } while (true);
2265}
2266
John Kessenich34fb0362016-05-03 23:17:20 -06002267// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002268// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002269//
2270// a op (b op (c op d))
2271//
2272// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002273// : initializer
2274// | conditional_expression
2275// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002276//
2277bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2278{
John Kessenich07354242016-07-01 19:58:06 -06002279 // initializer
2280 if (peekTokenClass(EHTokLeftBrace)) {
2281 if (acceptInitializer(node))
2282 return true;
2283
2284 expected("initializer");
2285 return false;
2286 }
2287
John Kessenich00957f82016-07-27 10:39:57 -06002288 // conditional_expression
2289 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002290 return false;
2291
John Kessenich07354242016-07-01 19:58:06 -06002292 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002293 TOperator assignOp = HlslOpMap::assignment(peek());
2294 if (assignOp == EOpNull)
2295 return true;
2296
John Kessenich00957f82016-07-27 10:39:57 -06002297 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002298 TSourceLoc loc = token.loc;
2299 advanceToken();
2300
John Kessenich00957f82016-07-27 10:39:57 -06002301 // conditional_expression assign_op conditional_expression ...
2302 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002303 // gets the right-to-left associativity.
2304 TIntermTyped* rightNode = nullptr;
2305 if (! acceptAssignmentExpression(rightNode)) {
2306 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002307 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002308 }
2309
John Kessenichd21baed2016-09-16 03:05:12 -06002310 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002311 node = parseContext.handleLvalue(loc, "assign", node);
2312
John Kessenichfea226b2016-07-28 17:53:56 -06002313 if (node == nullptr) {
2314 parseContext.error(loc, "could not create assignment", "", "");
2315 return false;
2316 }
John Kessenich34fb0362016-05-03 23:17:20 -06002317
2318 if (! peekTokenClass(EHTokComma))
2319 return true;
2320
2321 return true;
2322}
2323
John Kessenich00957f82016-07-27 10:39:57 -06002324// Accept a conditional expression, which associates right-to-left,
2325// accomplished by the "true" expression calling down to lower
2326// precedence levels than this level.
2327//
2328// conditional_expression
2329// : binary_expression
2330// | binary_expression QUESTION expression COLON assignment_expression
2331//
2332bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2333{
2334 // binary_expression
2335 if (! acceptBinaryExpression(node, PlLogicalOr))
2336 return false;
2337
2338 if (! acceptTokenClass(EHTokQuestion))
2339 return true;
2340
2341 TIntermTyped* trueNode = nullptr;
2342 if (! acceptExpression(trueNode)) {
2343 expected("expression after ?");
2344 return false;
2345 }
2346 TSourceLoc loc = token.loc;
2347
2348 if (! acceptTokenClass(EHTokColon)) {
2349 expected(":");
2350 return false;
2351 }
2352
2353 TIntermTyped* falseNode = nullptr;
2354 if (! acceptAssignmentExpression(falseNode)) {
2355 expected("expression after :");
2356 return false;
2357 }
2358
2359 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2360
2361 return true;
2362}
2363
John Kessenich34fb0362016-05-03 23:17:20 -06002364// Accept a binary expression, for binary operations that
2365// associate left-to-right. This is, it is implicit, for example
2366//
2367// ((a op b) op c) op d
2368//
2369// binary_expression
2370// : expression op expression op expression ...
2371//
2372// where 'expression' is the next higher level in precedence.
2373//
2374bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2375{
2376 if (precedenceLevel > PlMul)
2377 return acceptUnaryExpression(node);
2378
2379 // assignment_expression
2380 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2381 return false;
2382
John Kessenich34fb0362016-05-03 23:17:20 -06002383 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002384 TOperator op = HlslOpMap::binary(peek());
2385 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2386 if (tokenLevel < precedenceLevel)
2387 return true;
2388
John Kessenich34fb0362016-05-03 23:17:20 -06002389 // ... op
2390 TSourceLoc loc = token.loc;
2391 advanceToken();
2392
2393 // ... expression
2394 TIntermTyped* rightNode = nullptr;
2395 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2396 expected("expression");
2397 return false;
2398 }
2399
2400 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002401 if (node == nullptr) {
2402 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2403 return false;
2404 }
John Kessenich34fb0362016-05-03 23:17:20 -06002405 } while (true);
2406}
2407
2408// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002409// : (type) unary_expression
2410// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002411// | - unary_expression
2412// | ! unary_expression
2413// | ~ unary_expression
2414// | ++ unary_expression
2415// | -- unary_expression
2416// | postfix_expression
2417//
2418bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2419{
John Kessenich1cc1a282016-06-03 16:55:49 -06002420 // (type) unary_expression
2421 // Have to look two steps ahead, because this could be, e.g., a
2422 // postfix_expression instead, since that also starts with at "(".
2423 if (acceptTokenClass(EHTokLeftParen)) {
2424 TType castType;
2425 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002426 if (acceptTokenClass(EHTokRightParen)) {
2427 // We've matched "(type)" now, get the expression to cast
2428 TSourceLoc loc = token.loc;
2429 if (! acceptUnaryExpression(node))
2430 return false;
2431
2432 // Hook it up like a constructor
2433 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2434 if (constructorFunction == nullptr) {
2435 expected("type that can be constructed");
2436 return false;
2437 }
2438 TIntermTyped* arguments = nullptr;
2439 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2440 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2441
2442 return true;
2443 } else {
2444 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2445 // the '(int' part. We must back up twice.
2446 recedeToken();
2447 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002448 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002449 } else {
2450 // This isn't a type cast, but it still started "(", so if it is a
2451 // unary expression, it can only be a postfix_expression, so try that.
2452 // Back it up first.
2453 recedeToken();
2454 return acceptPostfixExpression(node);
2455 }
2456 }
2457
2458 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002459 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002460
John Kessenich1cc1a282016-06-03 16:55:49 -06002461 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002462 if (unaryOp == EOpNull)
2463 return acceptPostfixExpression(node);
2464
2465 // op unary_expression
2466 TSourceLoc loc = token.loc;
2467 advanceToken();
2468 if (! acceptUnaryExpression(node))
2469 return false;
2470
2471 // + is a no-op
2472 if (unaryOp == EOpAdd)
2473 return true;
2474
2475 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002476
2477 // These unary ops require lvalues
2478 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2479 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002480
2481 return node != nullptr;
2482}
2483
2484// postfix_expression
2485// : LEFT_PAREN expression RIGHT_PAREN
2486// | literal
2487// | constructor
2488// | identifier
2489// | function_call
2490// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2491// | postfix_expression DOT IDENTIFIER
2492// | postfix_expression INC_OP
2493// | postfix_expression DEC_OP
2494//
2495bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2496{
2497 // Not implemented as self-recursive:
2498 // The logical "right recursion" is done with an loop at the end
2499
2500 // idToken will pick up either a variable or a function name in a function call
2501 HlslToken idToken;
2502
John Kessenich21472ae2016-06-04 11:46:33 -06002503 // Find something before the postfix operations, as they can't operate
2504 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002505 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002506 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002507 if (! acceptExpression(node)) {
2508 expected("expression");
2509 return false;
2510 }
2511 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002512 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002513 return false;
2514 }
John Kessenich34fb0362016-05-03 23:17:20 -06002515 } else if (acceptLiteral(node)) {
John Kessenichecba76f2017-01-06 00:34:48 -07002516 // literal (nothing else to do yet), go on to the
John Kessenich34fb0362016-05-03 23:17:20 -06002517 } else if (acceptConstructor(node)) {
2518 // constructor (nothing else to do yet)
2519 } else if (acceptIdentifier(idToken)) {
2520 // identifier or function_call name
2521 if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002522 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002523 } else if (acceptFunctionCall(idToken, node)) {
2524 // function_call (nothing else to do yet)
2525 } else {
2526 expected("function call arguments");
2527 return false;
2528 }
John Kessenich21472ae2016-06-04 11:46:33 -06002529 } else {
2530 // nothing found, can't post operate
2531 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002532 }
2533
steve-lunarga2b01a02016-11-28 17:09:54 -07002534 // This is to guarantee we do this no matter how we get out of the stack frame.
2535 // This way there's no bug if an early return forgets to do it.
2536 struct tFinalize {
2537 tFinalize(HlslParseContext& p) : parseContext(p) { }
2538 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002539 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002540 private:
John Kessenichca71d942017-03-07 20:44:09 -07002541 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002542 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002543 } finalize(parseContext);
2544
2545 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2546 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2547 // level: hence the init and finalize. Even though in practice these must be
2548 // constants, they are parsed no matter what.
2549 parseContext.initFlattening();
2550
John Kessenich21472ae2016-06-04 11:46:33 -06002551 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002552 do {
2553 TSourceLoc loc = token.loc;
2554 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002555
John Kessenich34fb0362016-05-03 23:17:20 -06002556 // Consume only a valid post-unary operator, otherwise we are done.
2557 switch (postOp) {
2558 case EOpIndexDirectStruct:
2559 case EOpIndexIndirect:
2560 case EOpPostIncrement:
2561 case EOpPostDecrement:
2562 advanceToken();
2563 break;
2564 default:
2565 return true;
2566 }
John Kessenich87142c72016-03-12 20:24:24 -07002567
John Kessenich34fb0362016-05-03 23:17:20 -06002568 // We have a valid post-unary operator, process it.
2569 switch (postOp) {
2570 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002571 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002572 // DOT IDENTIFIER
2573 // includes swizzles and struct members
John Kessenich93a162a2016-06-17 17:16:27 -06002574 HlslToken field;
2575 if (! acceptIdentifier(field)) {
2576 expected("swizzle or member");
2577 return false;
2578 }
LoopDawg4886f692016-06-29 10:58:58 -06002579
2580 TIntermTyped* base = node; // preserve for method function calls
John Kessenich93a162a2016-06-17 17:16:27 -06002581 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002582
2583 // In the event of a method node, we look for an open paren and accept the function call.
steve-lunarga2b01a02016-11-28 17:09:54 -07002584 if (node != nullptr && node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) {
LoopDawg4886f692016-06-29 10:58:58 -06002585 if (! acceptFunctionCall(field, node, base)) {
2586 expected("function parameters");
2587 return false;
2588 }
2589 }
2590
John Kessenich34fb0362016-05-03 23:17:20 -06002591 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002592 }
John Kessenich34fb0362016-05-03 23:17:20 -06002593 case EOpIndexIndirect:
2594 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002595 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002596 TIntermTyped* indexNode = nullptr;
2597 if (! acceptExpression(indexNode) ||
2598 ! peekTokenClass(EHTokRightBracket)) {
2599 expected("expression followed by ']'");
2600 return false;
2601 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002602 advanceToken();
2603 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2604 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002605 }
2606 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002607 // INC_OP
2608 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002609 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002610 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002611 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002612 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002613 break;
2614 default:
2615 assert(0);
2616 break;
2617 }
2618 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002619}
2620
John Kessenichd016be12016-03-13 11:24:20 -06002621// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002622// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002623//
2624bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2625{
2626 // type
2627 TType type;
2628 if (acceptType(type)) {
2629 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2630 if (constructorFunction == nullptr)
2631 return false;
2632
2633 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002634 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002635 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002636 // It's possible this is a type keyword used as an identifier. Put the token back
2637 // for later use.
2638 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002639 return false;
2640 }
2641
2642 // hook it up
2643 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2644
2645 return true;
2646 }
2647
2648 return false;
2649}
2650
John Kessenich34fb0362016-05-03 23:17:20 -06002651// The function_call identifier was already recognized, and passed in as idToken.
2652//
2653// function_call
2654// : [idToken] arguments
2655//
LoopDawg4886f692016-06-29 10:58:58 -06002656bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base)
John Kessenich34fb0362016-05-03 23:17:20 -06002657{
John Kessenich4678ca92016-05-13 09:33:42 -06002658 // arguments
2659 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
2660 TIntermTyped* arguments = nullptr;
LoopDawg4886f692016-06-29 10:58:58 -06002661
2662 // methods have an implicit first argument of the calling object.
2663 if (base != nullptr)
2664 parseContext.handleFunctionArgument(function, arguments, base);
2665
John Kessenich4678ca92016-05-13 09:33:42 -06002666 if (! acceptArguments(function, arguments))
2667 return false;
2668
2669 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
2670
2671 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002672}
2673
John Kessenich87142c72016-03-12 20:24:24 -07002674// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002675// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002676//
John Kessenichd016be12016-03-13 11:24:20 -06002677// The arguments are pushed onto the 'function' argument list and
2678// onto the 'arguments' aggregate.
2679//
John Kessenich4678ca92016-05-13 09:33:42 -06002680bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002681{
John Kessenich078d7f22016-03-14 10:02:11 -06002682 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002683 if (! acceptTokenClass(EHTokLeftParen))
2684 return false;
2685
2686 do {
John Kessenichd016be12016-03-13 11:24:20 -06002687 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002688 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002689 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002690 break;
John Kessenichd016be12016-03-13 11:24:20 -06002691
2692 // hook it up
2693 parseContext.handleFunctionArgument(function, arguments, arg);
2694
John Kessenich078d7f22016-03-14 10:02:11 -06002695 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002696 if (! acceptTokenClass(EHTokComma))
2697 break;
2698 } while (true);
2699
John Kessenich078d7f22016-03-14 10:02:11 -06002700 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002701 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002702 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002703 return false;
2704 }
2705
2706 return true;
2707}
2708
2709bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2710{
2711 switch (token.tokenClass) {
2712 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002713 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002714 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002715 case EHTokUintConstant:
2716 node = intermediate.addConstantUnion(token.u, token.loc, true);
2717 break;
John Kessenich87142c72016-03-12 20:24:24 -07002718 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002719 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002720 break;
2721 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002722 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002723 break;
2724 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002725 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002726 break;
John Kessenich86f71382016-09-19 20:23:18 -06002727 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002728 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002729 break;
John Kessenich87142c72016-03-12 20:24:24 -07002730
2731 default:
2732 return false;
2733 }
2734
2735 advanceToken();
2736
2737 return true;
2738}
2739
John Kessenich5f934b02016-03-13 17:58:25 -06002740// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002741// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002742//
John Kessenich21472ae2016-06-04 11:46:33 -06002743bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002744{
John Kessenich21472ae2016-06-04 11:46:33 -06002745 TIntermAggregate* compoundStatement = nullptr;
2746
John Kessenich34fb0362016-05-03 23:17:20 -06002747 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002748 if (! acceptTokenClass(EHTokLeftBrace))
2749 return false;
2750
2751 // statement statement ...
2752 TIntermNode* statement = nullptr;
2753 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002754 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2755 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2756 branch->getFlowOp() == EOpDefault)) {
2757 // hook up individual subsequences within a switch statement
2758 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2759 compoundStatement = nullptr;
2760 } else {
2761 // hook it up to the growing compound statement
2762 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2763 }
John Kessenich5f934b02016-03-13 17:58:25 -06002764 }
John Kessenich34fb0362016-05-03 23:17:20 -06002765 if (compoundStatement)
2766 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002767
John Kessenich21472ae2016-06-04 11:46:33 -06002768 retStatement = compoundStatement;
2769
John Kessenich34fb0362016-05-03 23:17:20 -06002770 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002771 return acceptTokenClass(EHTokRightBrace);
2772}
2773
John Kessenich0d2b6de2016-06-05 11:23:11 -06002774bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2775{
2776 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002777 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002778 parseContext.popScope();
2779
2780 return result;
2781}
2782
John Kessenich077e0522016-06-09 02:02:17 -06002783bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002784{
John Kessenich077e0522016-06-09 02:02:17 -06002785 parseContext.pushScope();
2786 bool result = acceptCompoundStatement(statement);
2787 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002788
2789 return result;
2790}
2791
John Kessenich5f934b02016-03-13 17:58:25 -06002792// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002793// : attributes attributed_statement
2794//
2795// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002796// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002797// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002798// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002799// | declaration_statement
2800// | selection_statement
2801// | switch_statement
2802// | case_label
2803// | iteration_statement
2804// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002805//
2806bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2807{
John Kessenich21472ae2016-06-04 11:46:33 -06002808 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002809
John Kessenich21472ae2016-06-04 11:46:33 -06002810 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002811 TAttributeMap attributes;
2812 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002813
John Kessenich21472ae2016-06-04 11:46:33 -06002814 // attributed_statement
2815 switch (peek()) {
2816 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002817 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002818
John Kessenich21472ae2016-06-04 11:46:33 -06002819 case EHTokIf:
2820 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002821
John Kessenich21472ae2016-06-04 11:46:33 -06002822 case EHTokSwitch:
2823 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002824
John Kessenich21472ae2016-06-04 11:46:33 -06002825 case EHTokFor:
2826 case EHTokDo:
2827 case EHTokWhile:
2828 return acceptIterationStatement(statement);
2829
2830 case EHTokContinue:
2831 case EHTokBreak:
2832 case EHTokDiscard:
2833 case EHTokReturn:
2834 return acceptJumpStatement(statement);
2835
2836 case EHTokCase:
2837 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002838 case EHTokDefault:
2839 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002840
2841 case EHTokSemicolon:
2842 return acceptTokenClass(EHTokSemicolon);
2843
2844 case EHTokRightBrace:
2845 // Performance: not strictly necessary, but stops a bunch of hunting early,
2846 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002847 return false;
2848
John Kessenich21472ae2016-06-04 11:46:33 -06002849 default:
2850 {
2851 // declaration
2852 if (acceptDeclaration(statement))
2853 return true;
2854
2855 // expression
2856 TIntermTyped* node;
2857 if (acceptExpression(node))
2858 statement = node;
2859 else
2860 return false;
2861
2862 // SEMICOLON (following an expression)
2863 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002864 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002865 return false;
2866 }
2867 }
2868 }
2869
John Kessenich5f934b02016-03-13 17:58:25 -06002870 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002871}
2872
John Kessenich21472ae2016-06-04 11:46:33 -06002873// attributes
2874// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2875//
2876// attribute:
2877// : UNROLL
2878// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2879// | FASTOPT
2880// | ALLOW_UAV_CONDITION
2881// | BRANCH
2882// | FLATTEN
2883// | FORCECASE
2884// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06002885// | DOMAIN
2886// | EARLYDEPTHSTENCIL
2887// | INSTANCE
2888// | MAXTESSFACTOR
2889// | OUTPUTCONTROLPOINTS
2890// | OUTPUTTOPOLOGY
2891// | PARTITIONING
2892// | PATCHCONSTANTFUNC
2893// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06002894//
steve-lunarg1868b142016-10-20 13:07:10 -06002895void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06002896{
steve-lunarg1868b142016-10-20 13:07:10 -06002897 // For now, accept the [ XXX(X) ] syntax, but drop all but
2898 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06002899 // TODO: subset to correct set? Pass on?
2900 do {
steve-lunarg1868b142016-10-20 13:07:10 -06002901 HlslToken idToken;
2902
John Kessenich0d2b6de2016-06-05 11:23:11 -06002903 // LEFT_BRACKET?
2904 if (! acceptTokenClass(EHTokLeftBracket))
2905 return;
2906
2907 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06002908 if (acceptIdentifier(idToken)) {
2909 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06002910 } else if (! peekTokenClass(EHTokRightBracket)) {
2911 expected("identifier");
2912 advanceToken();
2913 }
2914
steve-lunarga22f7db2016-11-11 08:17:44 -07002915 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06002916
2917 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002918 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07002919 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06002920
John Kessenich0d2b6de2016-06-05 11:23:11 -06002921 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07002922 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07002923
steve-lunarga22f7db2016-11-11 08:17:44 -07002924 while (acceptAssignmentExpression(node)) {
2925 expectingExpression = false;
2926 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06002927 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07002928 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06002929 }
2930
steve-lunarga22f7db2016-11-11 08:17:44 -07002931 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06002932 if (! acceptTokenClass(EHTokRightParen))
2933 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07002934
2935 // Error for partial or missing expression
2936 if (expectingExpression || expressions->getSequence().empty())
2937 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06002938 }
2939
2940 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06002941 if (!acceptTokenClass(EHTokRightBracket)) {
2942 expected("]");
2943 return;
2944 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002945
steve-lunarg1868b142016-10-20 13:07:10 -06002946 // Add any values we found into the attribute map. This accepts
2947 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07002948 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002949 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06002950}
2951
John Kessenich0d2b6de2016-06-05 11:23:11 -06002952// selection_statement
2953// : IF LEFT_PAREN expression RIGHT_PAREN statement
2954// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
2955//
John Kessenich21472ae2016-06-04 11:46:33 -06002956bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
2957{
John Kessenich0d2b6de2016-06-05 11:23:11 -06002958 TSourceLoc loc = token.loc;
2959
2960 // IF
2961 if (! acceptTokenClass(EHTokIf))
2962 return false;
2963
2964 // so that something declared in the condition is scoped to the lifetimes
2965 // of the then-else statements
2966 parseContext.pushScope();
2967
2968 // LEFT_PAREN expression RIGHT_PAREN
2969 TIntermTyped* condition;
2970 if (! acceptParenExpression(condition))
2971 return false;
2972
2973 // create the child statements
2974 TIntermNodePair thenElse = { nullptr, nullptr };
2975
2976 // then statement
2977 if (! acceptScopedStatement(thenElse.node1)) {
2978 expected("then statement");
2979 return false;
2980 }
2981
2982 // ELSE
2983 if (acceptTokenClass(EHTokElse)) {
2984 // else statement
2985 if (! acceptScopedStatement(thenElse.node2)) {
2986 expected("else statement");
2987 return false;
2988 }
2989 }
2990
2991 // Put the pieces together
2992 statement = intermediate.addSelection(condition, thenElse, loc);
2993 parseContext.popScope();
2994
2995 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002996}
2997
John Kessenichd02dc5d2016-07-01 00:04:11 -06002998// switch_statement
2999// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3000//
John Kessenich21472ae2016-06-04 11:46:33 -06003001bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3002{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003003 // SWITCH
3004 TSourceLoc loc = token.loc;
3005 if (! acceptTokenClass(EHTokSwitch))
3006 return false;
3007
3008 // LEFT_PAREN expression RIGHT_PAREN
3009 parseContext.pushScope();
3010 TIntermTyped* switchExpression;
3011 if (! acceptParenExpression(switchExpression)) {
3012 parseContext.popScope();
3013 return false;
3014 }
3015
3016 // compound_statement
3017 parseContext.pushSwitchSequence(new TIntermSequence);
3018 bool statementOkay = acceptCompoundStatement(statement);
3019 if (statementOkay)
3020 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3021
3022 parseContext.popSwitchSequence();
3023 parseContext.popScope();
3024
3025 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003026}
3027
John Kessenich119f8f62016-06-05 15:44:07 -06003028// iteration_statement
3029// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3030// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3031// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3032//
3033// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003034bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3035{
John Kessenich119f8f62016-06-05 15:44:07 -06003036 TSourceLoc loc = token.loc;
3037 TIntermTyped* condition = nullptr;
3038
3039 EHlslTokenClass loop = peek();
3040 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3041
3042 // WHILE or DO or FOR
3043 advanceToken();
3044
3045 switch (loop) {
3046 case EHTokWhile:
3047 // so that something declared in the condition is scoped to the lifetime
3048 // of the while sub-statement
3049 parseContext.pushScope();
3050 parseContext.nestLooping();
3051
3052 // LEFT_PAREN condition RIGHT_PAREN
3053 if (! acceptParenExpression(condition))
3054 return false;
3055
3056 // statement
3057 if (! acceptScopedStatement(statement)) {
3058 expected("while sub-statement");
3059 return false;
3060 }
3061
3062 parseContext.unnestLooping();
3063 parseContext.popScope();
3064
3065 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3066
3067 return true;
3068
3069 case EHTokDo:
3070 parseContext.nestLooping();
3071
3072 if (! acceptTokenClass(EHTokLeftBrace))
3073 expected("{");
3074
3075 // statement
3076 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3077 expected("do sub-statement");
3078 return false;
3079 }
3080
3081 if (! acceptTokenClass(EHTokRightBrace))
3082 expected("}");
3083
3084 // WHILE
3085 if (! acceptTokenClass(EHTokWhile)) {
3086 expected("while");
3087 return false;
3088 }
3089
3090 // LEFT_PAREN condition RIGHT_PAREN
3091 TIntermTyped* condition;
3092 if (! acceptParenExpression(condition))
3093 return false;
3094
3095 if (! acceptTokenClass(EHTokSemicolon))
3096 expected(";");
3097
3098 parseContext.unnestLooping();
3099
3100 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3101
3102 return true;
3103
3104 case EHTokFor:
3105 {
3106 // LEFT_PAREN
3107 if (! acceptTokenClass(EHTokLeftParen))
3108 expected("(");
3109
3110 // so that something declared in the condition is scoped to the lifetime
3111 // of the for sub-statement
3112 parseContext.pushScope();
3113
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003114 // initializer
3115 TIntermNode* initNode = nullptr;
3116 if (! acceptControlDeclaration(initNode)) {
3117 TIntermTyped* initExpr = nullptr;
3118 acceptExpression(initExpr);
3119 initNode = initExpr;
3120 }
3121 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003122 if (! acceptTokenClass(EHTokSemicolon))
3123 expected(";");
3124
3125 parseContext.nestLooping();
3126
3127 // condition SEMI_COLON
3128 acceptExpression(condition);
3129 if (! acceptTokenClass(EHTokSemicolon))
3130 expected(";");
3131
3132 // iterator SEMI_COLON
3133 TIntermTyped* iterator = nullptr;
3134 acceptExpression(iterator);
3135 if (! acceptTokenClass(EHTokRightParen))
3136 expected(")");
3137
3138 // statement
3139 if (! acceptScopedStatement(statement)) {
3140 expected("for sub-statement");
3141 return false;
3142 }
3143
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003144 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003145
3146 parseContext.popScope();
3147 parseContext.unnestLooping();
3148
3149 return true;
3150 }
3151
3152 default:
3153 return false;
3154 }
John Kessenich21472ae2016-06-04 11:46:33 -06003155}
3156
3157// jump_statement
3158// : CONTINUE SEMICOLON
3159// | BREAK SEMICOLON
3160// | DISCARD SEMICOLON
3161// | RETURN SEMICOLON
3162// | RETURN expression SEMICOLON
3163//
3164bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3165{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003166 EHlslTokenClass jump = peek();
3167 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003168 case EHTokContinue:
3169 case EHTokBreak:
3170 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003171 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003172 advanceToken();
3173 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003174 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003175 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003176 return false;
3177 }
John Kessenich21472ae2016-06-04 11:46:33 -06003178
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003179 switch (jump) {
3180 case EHTokContinue:
3181 statement = intermediate.addBranch(EOpContinue, token.loc);
3182 break;
3183 case EHTokBreak:
3184 statement = intermediate.addBranch(EOpBreak, token.loc);
3185 break;
3186 case EHTokDiscard:
3187 statement = intermediate.addBranch(EOpKill, token.loc);
3188 break;
3189
3190 case EHTokReturn:
3191 {
3192 // expression
3193 TIntermTyped* node;
3194 if (acceptExpression(node)) {
3195 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003196 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003197 } else
3198 statement = intermediate.addBranch(EOpReturn, token.loc);
3199 break;
3200 }
3201
3202 default:
3203 assert(0);
3204 return false;
3205 }
3206
3207 // SEMICOLON
3208 if (! acceptTokenClass(EHTokSemicolon))
3209 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003210
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003211 return true;
3212}
John Kessenich21472ae2016-06-04 11:46:33 -06003213
John Kessenichd02dc5d2016-07-01 00:04:11 -06003214// case_label
3215// : CASE expression COLON
3216//
John Kessenich21472ae2016-06-04 11:46:33 -06003217bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3218{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003219 TSourceLoc loc = token.loc;
3220 if (! acceptTokenClass(EHTokCase))
3221 return false;
3222
3223 TIntermTyped* expression;
3224 if (! acceptExpression(expression)) {
3225 expected("case expression");
3226 return false;
3227 }
3228
3229 if (! acceptTokenClass(EHTokColon)) {
3230 expected(":");
3231 return false;
3232 }
3233
3234 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3235
3236 return true;
3237}
3238
3239// default_label
3240// : DEFAULT COLON
3241//
3242bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3243{
3244 TSourceLoc loc = token.loc;
3245 if (! acceptTokenClass(EHTokDefault))
3246 return false;
3247
3248 if (! acceptTokenClass(EHTokColon)) {
3249 expected(":");
3250 return false;
3251 }
3252
3253 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3254
3255 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003256}
3257
John Kessenich19b92ff2016-06-19 11:50:34 -06003258// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003259// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3260// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003261//
3262void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3263{
3264 arraySizes = nullptr;
3265
steve-lunarg7b211a32016-10-13 12:26:18 -06003266 // Early-out if there aren't any array dimensions
3267 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003268 return;
3269
steve-lunarg7b211a32016-10-13 12:26:18 -06003270 // 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 -06003271 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003272
3273 // Collect each array dimension.
3274 while (acceptTokenClass(EHTokLeftBracket)) {
3275 TSourceLoc loc = token.loc;
3276 TIntermTyped* sizeExpr = nullptr;
3277
John Kessenich057df292017-03-06 18:18:37 -07003278 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003279 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3280
3281 if (! acceptTokenClass(EHTokRightBracket)) {
3282 expected("]");
3283 return;
3284 }
3285
3286 if (hasArraySize) {
3287 TArraySize arraySize;
3288 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3289 arraySizes->addInnerSize(arraySize);
3290 } else {
3291 arraySizes->addInnerSize(0); // sized by initializers.
3292 }
steve-lunarg265c0612016-09-27 10:57:35 -06003293 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003294}
3295
John Kessenich630dd7d2016-06-12 23:52:12 -06003296// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003297// : COLON semantic // optional
3298// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3299// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003300// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003301// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003302//
John Kessenich854fe242017-03-02 14:30:59 -07003303// Return true if any tokens were accepted. That is,
3304// false can be returned on successfully recognizing nothing,
3305// not necessarily meaning bad syntax.
3306//
3307bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003308{
John Kessenich854fe242017-03-02 14:30:59 -07003309 bool found = false;
3310
John Kessenich630dd7d2016-06-12 23:52:12 -06003311 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003312 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003313 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003314 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003315 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003316 if (peekTokenClass(EHTokLayout))
3317 acceptLayoutQualifierList(qualifier);
3318 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003319 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003320 if (! acceptTokenClass(EHTokLeftParen)) {
3321 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003322 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003323 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003324 HlslToken locationToken;
3325 if (! acceptIdentifier(locationToken)) {
3326 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003327 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003328 }
3329 HlslToken componentToken;
3330 if (acceptTokenClass(EHTokDot)) {
3331 if (! acceptIdentifier(componentToken)) {
3332 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003333 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003334 }
3335 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003336 if (! acceptTokenClass(EHTokRightParen)) {
3337 expected(")");
3338 break;
3339 }
John Kessenich7735b942016-09-05 12:40:06 -06003340 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003341 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003342 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003343 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003344 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003345 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3346 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003347 if (! acceptTokenClass(EHTokLeftParen)) {
3348 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003349 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003350 }
John Kessenichb38f0712016-07-30 10:29:54 -06003351 HlslToken registerDesc; // for Type#
3352 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003353 if (! acceptIdentifier(registerDesc)) {
3354 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003355 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003356 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003357 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3358 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003359 // Then we didn't really see the registerDesc yet, it was
3360 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003361 profile = registerDesc;
3362 if (! acceptIdentifier(registerDesc)) {
3363 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003364 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003365 }
3366 }
John Kessenichb38f0712016-07-30 10:29:54 -06003367 int subComponent = 0;
3368 if (acceptTokenClass(EHTokLeftBracket)) {
3369 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3370 if (! peekTokenClass(EHTokIntConstant)) {
3371 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003372 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003373 }
3374 subComponent = token.i;
3375 advanceToken();
3376 if (! acceptTokenClass(EHTokRightBracket)) {
3377 expected("]");
3378 break;
3379 }
3380 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003381 // (COMMA SPACEN)opt
3382 HlslToken spaceDesc;
3383 if (acceptTokenClass(EHTokComma)) {
3384 if (! acceptIdentifier(spaceDesc)) {
3385 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003386 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003387 }
3388 }
3389 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003390 if (! acceptTokenClass(EHTokRightParen)) {
3391 expected(")");
3392 break;
3393 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003394 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003395 } else {
3396 // semantic, in idToken.string
John Kessenich7735b942016-09-05 12:40:06 -06003397 parseContext.handleSemantic(idToken.loc, qualifier, *idToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003398 }
John Kessenich854fe242017-03-02 14:30:59 -07003399 } else if (peekTokenClass(EHTokLeftAngle)) {
3400 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003401 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003402 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003403 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003404
John Kessenich630dd7d2016-06-12 23:52:12 -06003405 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003406
3407 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003408}
3409
John Kesseniche01a9bc2016-03-12 20:11:22 -07003410} // end namespace glslang