blob: 2329246d7a3cb9a7731a649491c91028ccbbce73 [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 Kessenich7a41f962017-03-22 11:38:22 -060078// IDENTIFIER
79// THIS
80// type that can be used as IDENTIFIER
81//
John Kessenichaecd4972016-03-14 10:46:34 -060082// Only process the next token if it is an identifier.
83// Return true if it was an identifier.
84bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
85{
John Kessenich7a41f962017-03-22 11:38:22 -060086 // IDENTIFIER
John Kessenichaecd4972016-03-14 10:46:34 -060087 if (peekTokenClass(EHTokIdentifier)) {
88 idToken = token;
89 advanceToken();
90 return true;
91 }
92
John Kessenich7a41f962017-03-22 11:38:22 -060093 // THIS
94 // -> maps to the IDENTIFIER spelled with the internal special name for 'this'
95 if (peekTokenClass(EHTokThis)) {
96 idToken = token;
97 advanceToken();
98 idToken.tokenClass = EHTokIdentifier;
99 idToken.string = NewPoolTString(intermediate.implicitThisName);
100 return true;
101 }
102
103 // type that can be used as IDENTIFIER
104
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700105 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
106 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
107 // valid identifier, nor is "linear". This code special cases the known instances of this, so
108 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
John Kessenichecba76f2017-01-06 00:34:48 -0700109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 TString* idString = nullptr;
111 switch (peek()) {
112 case EHTokSample: idString = NewPoolTString("sample"); break;
113 case EHTokHalf: idString = NewPoolTString("half"); break;
114 case EHTokBool: idString = NewPoolTString("bool"); break;
115 case EHTokFloat: idString = NewPoolTString("float"); break;
116 case EHTokDouble: idString = NewPoolTString("double"); break;
117 case EHTokInt: idString = NewPoolTString("int"); break;
118 case EHTokUint: idString = NewPoolTString("uint"); break;
119 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
120 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
121 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
122 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
123 default:
124 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700125 }
126
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700127 token.string = idString;
128 token.tokenClass = EHTokIdentifier;
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700129 idToken = token;
130
131 advanceToken();
132
133 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600134}
135
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136// compilationUnit
John Kessenich8f9fdc92017-03-30 16:22:26 -0600137// : declaration_list EOF
John Kesseniche01a9bc2016-03-12 20:11:22 -0700138//
139bool HlslGrammar::acceptCompilationUnit()
140{
John Kessenichd016be12016-03-13 11:24:20 -0600141 TIntermNode* unitNode = nullptr;
142
John Kessenich8f9fdc92017-03-30 16:22:26 -0600143 if (! acceptDeclarationList(unitNode))
144 return false;
steve-lunargcb88de52016-08-03 07:04:18 -0600145
John Kessenich8f9fdc92017-03-30 16:22:26 -0600146 if (! peekTokenClass(EHTokNone))
147 return false;
John Kesseniche01a9bc2016-03-12 20:11:22 -0700148
John Kessenichd016be12016-03-13 11:24:20 -0600149 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700150 if (unitNode && !unitNode->getAsAggregate())
151 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600152 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600153
John Kesseniche01a9bc2016-03-12 20:11:22 -0700154 return true;
155}
156
John Kessenich8f9fdc92017-03-30 16:22:26 -0600157// Recognize the following, but with the extra condition that it can be
158// successfully terminated by EOF or '}'.
159//
160// declaration_list
161// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
162//
163// declaration_or_semicolon
164// : declaration
165// : SEMICOLON
166//
167bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
168{
169 do {
170 // HLSL allows extra semicolons between global declarations
171 do { } while (acceptTokenClass(EHTokSemicolon));
172
173 // EOF or RIGHT_BRACE
174 if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
175 return true;
176
177 // declaration
178 if (! acceptDeclaration(nodeList))
179 return false;
180 } while (true);
181
182 return true;
183}
184
LoopDawg4886f692016-06-29 10:58:58 -0600185// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700186// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600187//
188// sampler_state_assignment
189// : sampler_state_identifier EQUAL value SEMICOLON
190//
191// sampler_state_identifier
192// : ADDRESSU
193// | ADDRESSV
194// | ADDRESSW
195// | BORDERCOLOR
196// | FILTER
197// | MAXANISOTROPY
198// | MAXLOD
199// | MINLOD
200// | MIPLODBIAS
201//
202bool HlslGrammar::acceptSamplerState()
203{
204 // TODO: this should be genericized to accept a list of valid tokens and
205 // return token/value pairs. Presently it is specific to texture values.
206
207 if (! acceptTokenClass(EHTokLeftBrace))
208 return true;
209
210 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700211
LoopDawg4886f692016-06-29 10:58:58 -0600212 do {
213 // read state name
214 HlslToken state;
215 if (! acceptIdentifier(state))
216 break; // end of list
217
218 // FXC accepts any case
219 TString stateName = *state.string;
220 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
221
222 if (! acceptTokenClass(EHTokAssign)) {
223 expected("assign");
224 return false;
225 }
226
227 if (stateName == "minlod" || stateName == "maxlod") {
228 if (! peekTokenClass(EHTokIntConstant)) {
229 expected("integer");
230 return false;
231 }
232
233 TIntermTyped* lod = nullptr;
234 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
235 return false;
236 } else if (stateName == "maxanisotropy") {
237 if (! peekTokenClass(EHTokIntConstant)) {
238 expected("integer");
239 return false;
240 }
241
242 TIntermTyped* maxAnisotropy = nullptr;
243 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
244 return false;
245 } else if (stateName == "filter") {
246 HlslToken filterMode;
247 if (! acceptIdentifier(filterMode)) {
248 expected("filter mode");
249 return false;
250 }
251 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
252 HlslToken addrMode;
253 if (! acceptIdentifier(addrMode)) {
254 expected("texture address mode");
255 return false;
256 }
257 } else if (stateName == "miplodbias") {
258 TIntermTyped* lodBias = nullptr;
259 if (! acceptLiteral(lodBias)) {
260 expected("lod bias");
261 return false;
262 }
263 } else if (stateName == "bordercolor") {
264 return false;
265 } else {
266 expected("texture state");
267 return false;
268 }
269
270 // SEMICOLON
271 if (! acceptTokenClass(EHTokSemicolon)) {
272 expected("semicolon");
273 return false;
274 }
275 } while (true);
276
277 if (! acceptTokenClass(EHTokRightBrace))
278 return false;
279
280 return true;
281}
282
283// sampler_declaration_dx9
284// : SAMPLER identifier EQUAL sampler_type sampler_state
285//
John Kesseniche4821e42016-07-16 10:19:43 -0600286bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600287{
288 if (! acceptTokenClass(EHTokSampler))
289 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700290
LoopDawg4886f692016-06-29 10:58:58 -0600291 // TODO: remove this when DX9 style declarations are implemented.
292 unimplemented("Direct3D 9 sampler declaration");
293
294 // read sampler name
295 HlslToken name;
296 if (! acceptIdentifier(name)) {
297 expected("sampler name");
298 return false;
299 }
300
301 if (! acceptTokenClass(EHTokAssign)) {
302 expected("=");
303 return false;
304 }
305
306 return false;
307}
308
John Kesseniche01a9bc2016-03-12 20:11:22 -0700309// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600310// : sampler_declaration_dx9 post_decls SEMICOLON
John Kessenich13075c62017-04-11 09:51:32 -0600311// | fully_specified_type declarator_list SEMICOLON(optional for cbuffer/tbuffer)
John Kessenich630dd7d2016-06-12 23:52:12 -0600312// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600313// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600314// | typedef declaration
John Kessenich8f9fdc92017-03-30 16:22:26 -0600315// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
John Kessenich87142c72016-03-12 20:24:24 -0700316//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600317// declarator_list
318// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600319//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600320// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600321// : identifier array_specifier post_decls
322// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600323// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600324//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600325// Parsing has to go pretty far in to know whether it's a variable, prototype, or
326// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600327// as above. (The 'identifier' in the first item in init_declarator list is the
328// same as 'identifier' for function declarations.)
329//
John Kessenichca71d942017-03-07 20:44:09 -0700330// This can generate more than one subtree, one per initializer or a function body.
331// All initializer subtrees are put in their own aggregate node, making one top-level
332// node for all the initializers. Each function created is a top-level node to grow
333// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600334//
John Kessenichca71d942017-03-07 20:44:09 -0700335// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
336// each top-level node the declaration creates. Otherwise, if only one top-level
337// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700338//
John Kessenichca71d942017-03-07 20:44:09 -0700339bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700340{
John Kessenich8f9fdc92017-03-30 16:22:26 -0600341 // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
342 if (acceptTokenClass(EHTokNamespace)) {
343 HlslToken namespaceToken;
344 if (!acceptIdentifier(namespaceToken)) {
345 expected("namespace name");
346 return false;
347 }
348 parseContext.pushNamespace(*namespaceToken.string);
349 if (!acceptTokenClass(EHTokLeftBrace)) {
350 expected("{");
351 return false;
352 }
353 if (!acceptDeclarationList(nodeList)) {
354 expected("declaration list");
355 return false;
356 }
357 if (!acceptTokenClass(EHTokRightBrace)) {
358 expected("}");
359 return false;
360 }
361 parseContext.popNamespace();
362 return true;
363 }
364
John Kessenich54ee28f2017-03-11 14:13:00 -0700365 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600366
steve-lunarg1868b142016-10-20 13:07:10 -0600367 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700368 TFunctionDeclarator declarator;
369 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600370
John Kessenich5e69ec62016-07-05 00:02:40 -0600371 // typedef
372 bool typedefDecl = acceptTokenClass(EHTokTypedef);
373
John Kesseniche82061d2016-09-27 14:38:57 -0600374 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600375
376 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600377 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
378 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
379 // HLSL shaders, this will have to be a master level switch
380 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700381 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700382 // if (acceptSamplerDeclarationDX9(declaredType))
383 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600384
385 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700386 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700387 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600388
John Kessenich87142c72016-03-12 20:24:24 -0700389 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600390 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700391 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 while (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600393 const TString *fullName = idToken.string;
394 if (parseContext.symbolTable.atGlobalLevel())
395 parseContext.getFullNamespaceName(fullName);
John Kessenich78388722017-03-08 18:53:51 -0700396 if (peekTokenClass(EHTokLeftParen)) {
397 // looks like function parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600398
John Kessenich78388722017-03-08 18:53:51 -0700399 // Potentially rename shader entry point function. No-op most of the time.
John Kessenich8f9fdc92017-03-30 16:22:26 -0600400 parseContext.renameShaderFunction(fullName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600401
John Kessenich78388722017-03-08 18:53:51 -0700402 // function_parameters
John Kessenich8f9fdc92017-03-30 16:22:26 -0600403 declarator.function = new TFunction(fullName, declaredType);
John Kessenich088d52b2017-03-11 17:55:28 -0700404 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700405 expected("function parameter list");
406 return false;
407 }
408
John Kessenich630dd7d2016-06-12 23:52:12 -0600409 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700410 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600411
John Kessenichd5ed0b62016-07-04 17:32:45 -0600412 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700413 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600414 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700415 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600416 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600417 if (typedefDecl)
418 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700419 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600420 } else {
421 if (typedefDecl)
422 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700423 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600424 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600425 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600426 // A variable declaration. Fix the storage qualifier if it's a global.
427 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
428 declaredType.getQualifier().storage = EvqUniform;
429
John Kessenichecba76f2017-01-06 00:34:48 -0700430 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600431 // the number of types can expand when arrayness is different.
432 TType variableType;
433 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600434
John Kesseniche82061d2016-09-27 14:38:57 -0600435 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600436 TArraySizes* arraySizes = nullptr;
437 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600438
John Kesseniche82061d2016-09-27 14:38:57 -0600439 // Fix arrayness in the variableType
440 if (declaredType.isImplicitlySizedArray()) {
441 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
442 // of different sizes, for this case sharing the shallow copy of arrayness
443 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
444 variableType.newArraySizes(declaredType.getArraySizes());
445 }
446 if (arraySizes || variableType.isArray()) {
447 // In the most general case, arrayness is potentially coming both from the
448 // declared type and from the variable: "int[] a[];" or just one or the other.
449 // Merge it all to the variableType, so all arrayness is part of the variableType.
450 parseContext.arrayDimMerge(variableType, arraySizes);
451 }
452
LoopDawg4886f692016-06-29 10:58:58 -0600453 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600454 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600455 if (! acceptSamplerState())
456 return false;
457 }
458
John Kessenichd5ed0b62016-07-04 17:32:45 -0600459 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600460 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600461
462 // EQUAL assignment_expression
463 TIntermTyped* expressionNode = nullptr;
464 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600465 if (typedefDecl)
466 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600467 if (! acceptAssignmentExpression(expressionNode)) {
468 expected("initializer");
469 return false;
470 }
471 }
472
John Kessenich6dbc0a72016-09-27 19:13:05 -0600473 // TODO: things scoped within an annotation need their own name space;
474 // TODO: strings are not yet handled.
475 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
476 if (typedefDecl)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600477 parseContext.declareTypedef(idToken.loc, *fullName, variableType);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600478 else if (variableType.getBasicType() == EbtBlock) {
steve-lunarga766b832017-04-25 09:30:28 -0600479 parseContext.declareBlock(idToken.loc, variableType, fullName,
480 variableType.isArray() ? &variableType.getArraySizes() : nullptr);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600481 parseContext.declareStructBufferCounter(idToken.loc, variableType, *fullName);
482 } else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700483 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600484 // this isn't really an individual variable, but a member of the $Global buffer
John Kessenich8f9fdc92017-03-30 16:22:26 -0600485 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600486 } else {
487 // Declare the variable and add any initializer code to the AST.
488 // The top-level node is always made into an aggregate, as that's
489 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700490 initializers = intermediate.growAggregate(initializers,
John Kessenich8f9fdc92017-03-30 16:22:26 -0600491 parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
John Kessenichca71d942017-03-07 20:44:09 -0700492 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600493 }
494 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600495 }
John Kessenich5f934b02016-03-13 17:58:25 -0600496 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600497
498 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700499 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600500 continue;
501 }
502 };
503
John Kessenichca71d942017-03-07 20:44:09 -0700504 // The top-level initializer node is a sequence.
505 if (initializers != nullptr)
506 initializers->setOperator(EOpSequence);
507
508 // Add the initializers' aggregate to the nodeList we were handed.
509 if (nodeList)
510 nodeList = intermediate.growAggregate(nodeList, initializers);
511 else
512 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700513
John Kessenich13075c62017-04-11 09:51:32 -0600514 // SEMICOLON(optional for cbuffer/tbuffer)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600515 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich13075c62017-04-11 09:51:32 -0600516 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma) {
517 // This may have been a false detection of what appeared to be a declaration, but
518 // was actually an assignment such as "float = 4", where "float" is an identifier.
519 // We put the token back to let further parsing happen for cases where that may
520 // happen. This errors on the side of caution, and mostly triggers the error.
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700521 recedeToken();
John Kessenich13075c62017-04-11 09:51:32 -0600522 return false;
523 } else if (declaredType.getBasicType() == EbtBlock) {
524 // cbuffer, et. al. (but not struct) don't have an ending semicolon
525 return true;
526 } else {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700527 expected(";");
John Kessenich13075c62017-04-11 09:51:32 -0600528 return false;
529 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600530 }
John Kessenichecba76f2017-01-06 00:34:48 -0700531
John Kesseniche01a9bc2016-03-12 20:11:22 -0700532 return true;
533}
534
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600535// control_declaration
536// : fully_specified_type identifier EQUAL expression
537//
538bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
539{
540 node = nullptr;
541
542 // fully_specified_type
543 TType type;
544 if (! acceptFullySpecifiedType(type))
545 return false;
546
John Kessenich057df292017-03-06 18:18:37 -0700547 // filter out type casts
548 if (peekTokenClass(EHTokLeftParen)) {
549 recedeToken();
550 return false;
551 }
552
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600553 // identifier
554 HlslToken idToken;
555 if (! acceptIdentifier(idToken)) {
556 expected("identifier");
557 return false;
558 }
559
560 // EQUAL
561 TIntermTyped* expressionNode = nullptr;
562 if (! acceptTokenClass(EHTokAssign)) {
563 expected("=");
564 return false;
565 }
566
567 // expression
568 if (! acceptExpression(expressionNode)) {
569 expected("initializer");
570 return false;
571 }
572
John Kesseniche82061d2016-09-27 14:38:57 -0600573 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600574
575 return true;
576}
577
John Kessenich87142c72016-03-12 20:24:24 -0700578// fully_specified_type
579// : type_specifier
580// | type_qualifier type_specifier
581//
582bool HlslGrammar::acceptFullySpecifiedType(TType& type)
583{
John Kessenich54ee28f2017-03-11 14:13:00 -0700584 TIntermNode* nodeList = nullptr;
585 return acceptFullySpecifiedType(type, nodeList);
586}
587bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
588{
John Kessenich87142c72016-03-12 20:24:24 -0700589 // type_qualifier
590 TQualifier qualifier;
591 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600592 if (! acceptQualifier(qualifier))
593 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600594 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700595
596 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700597 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700598 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700599 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700600 // qualifier. Back it out, if we did.
601 if (qualifier.sample)
602 recedeToken();
603
John Kessenich87142c72016-03-12 20:24:24 -0700604 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700605 }
John Kessenich3d157c52016-07-25 16:05:33 -0600606 if (type.getBasicType() == EbtBlock) {
607 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600608 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600609 // further, it can create an anonymous instance of the block
John Kessenich13075c62017-04-11 09:51:32 -0600610 if (peek() != EHTokIdentifier)
John Kessenich3d157c52016-07-25 16:05:33 -0600611 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600612 } else {
613 // Some qualifiers are set when parsing the type. Merge those with
614 // whatever comes from acceptQualifier.
615 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700616
steve-lunargbb0183f2016-10-04 16:58:14 -0600617 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600618 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700619
steve-lunarg08e0c082017-03-29 20:01:13 -0600620 if (type.getQualifier().storage == EvqOut ||
steve-lunarg5da1f032017-02-12 17:50:28 -0700621 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700622 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700623 qualifier.readonly = type.getQualifier().readonly;
624 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700625
steve-lunarg08e0c082017-03-29 20:01:13 -0600626 if (type.getQualifier().builtIn != EbvNone)
627 qualifier.builtIn = type.getQualifier().builtIn;
628
steve-lunargf49cdf42016-11-17 15:04:20 -0700629 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600630 }
John Kessenich87142c72016-03-12 20:24:24 -0700631
632 return true;
633}
634
John Kessenich630dd7d2016-06-12 23:52:12 -0600635// type_qualifier
636// : qualifier qualifier ...
637//
638// Zero or more of these, so this can't return false.
639//
John Kessenichb9e39122016-08-17 10:22:08 -0600640bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700641{
John Kessenich630dd7d2016-06-12 23:52:12 -0600642 do {
643 switch (peek()) {
644 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600645 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600646 break;
647 case EHTokExtern:
648 // TODO: no meaning in glslang?
649 break;
650 case EHTokShared:
651 // TODO: hint
652 break;
653 case EHTokGroupShared:
654 qualifier.storage = EvqShared;
655 break;
656 case EHTokUniform:
657 qualifier.storage = EvqUniform;
658 break;
659 case EHTokConst:
660 qualifier.storage = EvqConst;
661 break;
662 case EHTokVolatile:
663 qualifier.volatil = true;
664 break;
665 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600666 qualifier.smooth = true;
667 break;
668 case EHTokCentroid:
669 qualifier.centroid = true;
670 break;
671 case EHTokNointerpolation:
672 qualifier.flat = true;
673 break;
674 case EHTokNoperspective:
675 qualifier.nopersp = true;
676 break;
677 case EHTokSample:
678 qualifier.sample = true;
679 break;
680 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600681 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600682 break;
683 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600684 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600685 break;
686 case EHTokPrecise:
687 qualifier.noContraction = true;
688 break;
LoopDawg9249c702016-07-12 20:44:32 -0600689 case EHTokIn:
690 qualifier.storage = EvqIn;
691 break;
692 case EHTokOut:
693 qualifier.storage = EvqOut;
694 break;
695 case EHTokInOut:
696 qualifier.storage = EvqInOut;
697 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600698 case EHTokLayout:
699 if (! acceptLayoutQualifierList(qualifier))
700 return false;
701 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700702 case EHTokGloballyCoherent:
703 qualifier.coherent = true;
704 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600705 case EHTokInline:
706 // TODO: map this to SPIR-V function control
707 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700708
709 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
710 // for output variables.
711 case EHTokPoint:
712 qualifier.storage = EvqIn;
713 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
714 return false;
715 break;
716 case EHTokLine:
717 qualifier.storage = EvqIn;
718 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
719 return false;
720 break;
721 case EHTokTriangle:
722 qualifier.storage = EvqIn;
723 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
724 return false;
725 break;
726 case EHTokLineAdj:
727 qualifier.storage = EvqIn;
728 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
729 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700730 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700731 case EHTokTriangleAdj:
732 qualifier.storage = EvqIn;
733 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
734 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700735 break;
736
John Kessenich630dd7d2016-06-12 23:52:12 -0600737 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600738 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600739 }
740 advanceToken();
741 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700742}
743
John Kessenichb9e39122016-08-17 10:22:08 -0600744// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600745// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600746//
747// layout_qualifier
748// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600749// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600750//
751// Zero or more of these, so this can't return false.
752//
753bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
754{
755 if (! acceptTokenClass(EHTokLayout))
756 return false;
757
758 // LEFT_PAREN
759 if (! acceptTokenClass(EHTokLeftParen))
760 return false;
761
762 do {
763 // identifier
764 HlslToken idToken;
765 if (! acceptIdentifier(idToken))
766 break;
767
768 // EQUAL expression
769 if (acceptTokenClass(EHTokAssign)) {
770 TIntermTyped* expr;
771 if (! acceptConditionalExpression(expr)) {
772 expected("expression");
773 return false;
774 }
775 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
776 } else
777 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
778
779 // COMMA
780 if (! acceptTokenClass(EHTokComma))
781 break;
782 } while (true);
783
784 // RIGHT_PAREN
785 if (! acceptTokenClass(EHTokRightParen)) {
786 expected(")");
787 return false;
788 }
789
790 return true;
791}
792
LoopDawg6daaa4f2016-06-23 19:13:48 -0600793// template_type
794// : FLOAT
795// | DOUBLE
796// | INT
797// | DWORD
798// | UINT
799// | BOOL
800//
steve-lunargf49cdf42016-11-17 15:04:20 -0700801bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600802{
803 switch (peek()) {
804 case EHTokFloat:
805 basicType = EbtFloat;
806 break;
807 case EHTokDouble:
808 basicType = EbtDouble;
809 break;
810 case EHTokInt:
811 case EHTokDword:
812 basicType = EbtInt;
813 break;
814 case EHTokUint:
815 basicType = EbtUint;
816 break;
817 case EHTokBool:
818 basicType = EbtBool;
819 break;
820 default:
821 return false;
822 }
823
824 advanceToken();
825
826 return true;
827}
828
829// vector_template_type
830// : VECTOR
831// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
832//
833bool HlslGrammar::acceptVectorTemplateType(TType& type)
834{
835 if (! acceptTokenClass(EHTokVector))
836 return false;
837
838 if (! acceptTokenClass(EHTokLeftAngle)) {
839 // in HLSL, 'vector' alone means float4.
840 new(&type) TType(EbtFloat, EvqTemporary, 4);
841 return true;
842 }
843
844 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700845 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600846 expected("scalar type");
847 return false;
848 }
849
850 // COMMA
851 if (! acceptTokenClass(EHTokComma)) {
852 expected(",");
853 return false;
854 }
855
856 // integer
857 if (! peekTokenClass(EHTokIntConstant)) {
858 expected("literal integer");
859 return false;
860 }
861
862 TIntermTyped* vecSize;
863 if (! acceptLiteral(vecSize))
864 return false;
865
866 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
867
868 new(&type) TType(basicType, EvqTemporary, vecSizeI);
869
870 if (vecSizeI == 1)
871 type.makeVector();
872
873 if (!acceptTokenClass(EHTokRightAngle)) {
874 expected("right angle bracket");
875 return false;
876 }
877
878 return true;
879}
880
881// matrix_template_type
882// : MATRIX
883// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
884//
885bool HlslGrammar::acceptMatrixTemplateType(TType& type)
886{
887 if (! acceptTokenClass(EHTokMatrix))
888 return false;
889
890 if (! acceptTokenClass(EHTokLeftAngle)) {
891 // in HLSL, 'matrix' alone means float4x4.
892 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
893 return true;
894 }
895
896 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700897 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600898 expected("scalar type");
899 return false;
900 }
901
902 // COMMA
903 if (! acceptTokenClass(EHTokComma)) {
904 expected(",");
905 return false;
906 }
907
908 // integer rows
909 if (! peekTokenClass(EHTokIntConstant)) {
910 expected("literal integer");
911 return false;
912 }
913
914 TIntermTyped* rows;
915 if (! acceptLiteral(rows))
916 return false;
917
918 // COMMA
919 if (! acceptTokenClass(EHTokComma)) {
920 expected(",");
921 return false;
922 }
John Kessenichecba76f2017-01-06 00:34:48 -0700923
LoopDawg6daaa4f2016-06-23 19:13:48 -0600924 // integer cols
925 if (! peekTokenClass(EHTokIntConstant)) {
926 expected("literal integer");
927 return false;
928 }
929
930 TIntermTyped* cols;
931 if (! acceptLiteral(cols))
932 return false;
933
934 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600935 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
936 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600937
938 if (!acceptTokenClass(EHTokRightAngle)) {
939 expected("right angle bracket");
940 return false;
941 }
942
943 return true;
944}
945
steve-lunargf49cdf42016-11-17 15:04:20 -0700946// layout_geometry
947// : LINESTREAM
948// | POINTSTREAM
949// | TRIANGLESTREAM
950//
951bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
952{
953 // read geometry type
954 const EHlslTokenClass geometryType = peek();
955
956 switch (geometryType) {
957 case EHTokPointStream: geometry = ElgPoints; break;
958 case EHTokLineStream: geometry = ElgLineStrip; break;
959 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
960 default:
961 return false; // not a layout geometry
962 }
963
964 advanceToken(); // consume the layout keyword
965 return true;
966}
967
steve-lunarg858c9282017-01-07 08:54:10 -0700968// tessellation_decl_type
969// : INPUTPATCH
970// | OUTPUTPATCH
971//
steve-lunarg067eb9b2017-04-01 15:34:48 -0600972bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
steve-lunarg858c9282017-01-07 08:54:10 -0700973{
974 // read geometry type
975 const EHlslTokenClass tessType = peek();
976
977 switch (tessType) {
steve-lunarg067eb9b2017-04-01 15:34:48 -0600978 case EHTokInputPatch: patchType = EbvInputPatch; break;
979 case EHTokOutputPatch: patchType = EbvOutputPatch; break;
steve-lunarg858c9282017-01-07 08:54:10 -0700980 default:
981 return false; // not a tessellation decl
982 }
983
984 advanceToken(); // consume the keyword
985 return true;
986}
987
988// tessellation_patch_template_type
989// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
990//
991bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
992{
steve-lunarg067eb9b2017-04-01 15:34:48 -0600993 TBuiltInVariable patchType;
994
995 if (! acceptTessellationDeclType(patchType))
steve-lunarg858c9282017-01-07 08:54:10 -0700996 return false;
997
998 if (! acceptTokenClass(EHTokLeftAngle))
999 return false;
1000
1001 if (! acceptType(type)) {
1002 expected("tessellation patch type");
1003 return false;
1004 }
1005
1006 if (! acceptTokenClass(EHTokComma))
1007 return false;
1008
1009 // integer size
1010 if (! peekTokenClass(EHTokIntConstant)) {
1011 expected("literal integer");
1012 return false;
1013 }
1014
1015 TIntermTyped* size;
1016 if (! acceptLiteral(size))
1017 return false;
1018
1019 TArraySizes* arraySizes = new TArraySizes;
1020 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1021 type.newArraySizes(*arraySizes);
steve-lunarg067eb9b2017-04-01 15:34:48 -06001022 type.getQualifier().builtIn = patchType;
steve-lunarg858c9282017-01-07 08:54:10 -07001023
1024 if (! acceptTokenClass(EHTokRightAngle)) {
1025 expected("right angle bracket");
1026 return false;
1027 }
1028
1029 return true;
1030}
1031
steve-lunargf49cdf42016-11-17 15:04:20 -07001032// stream_out_template_type
1033// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1034//
1035bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1036{
1037 geometry = ElgNone;
1038
1039 if (! acceptOutputPrimitiveGeometry(geometry))
1040 return false;
1041
1042 if (! acceptTokenClass(EHTokLeftAngle))
1043 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001044
steve-lunargf49cdf42016-11-17 15:04:20 -07001045 if (! acceptType(type)) {
1046 expected("stream output type");
1047 return false;
1048 }
1049
steve-lunarg08e0c082017-03-29 20:01:13 -06001050 type.getQualifier().storage = EvqOut;
1051 type.getQualifier().builtIn = EbvGsOutputStream;
steve-lunargf49cdf42016-11-17 15:04:20 -07001052
1053 if (! acceptTokenClass(EHTokRightAngle)) {
1054 expected("right angle bracket");
1055 return false;
1056 }
1057
1058 return true;
1059}
John Kessenichecba76f2017-01-06 00:34:48 -07001060
John Kessenicha1e2d492016-09-20 13:22:58 -06001061// annotations
1062// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001063//
John Kessenicha1e2d492016-09-20 13:22:58 -06001064bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001065{
John Kessenicha1e2d492016-09-20 13:22:58 -06001066 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001067 return false;
1068
John Kessenicha1e2d492016-09-20 13:22:58 -06001069 // note that we are nesting a name space
1070 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001071
1072 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1073 do {
1074 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1075 while (acceptTokenClass(EHTokSemicolon))
1076 ;
1077
1078 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001079 break;
John Kessenich86f71382016-09-19 20:23:18 -06001080
1081 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001082 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001083 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001084 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001085 return false;
1086 }
1087 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001088
1089 parseContext.unnestAnnotations();
1090 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001091}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001092
LoopDawg4886f692016-06-29 10:58:58 -06001093// sampler_type
1094// : SAMPLER
1095// | SAMPLER1D
1096// | SAMPLER2D
1097// | SAMPLER3D
1098// | SAMPLERCUBE
1099// | SAMPLERSTATE
1100// | SAMPLERCOMPARISONSTATE
1101bool HlslGrammar::acceptSamplerType(TType& type)
1102{
1103 // read sampler type
1104 const EHlslTokenClass samplerType = peek();
1105
LoopDawga78b0292016-07-19 14:28:05 -06001106 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001107 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001108
LoopDawga78b0292016-07-19 14:28:05 -06001109 bool isShadow = false;
1110
LoopDawg4886f692016-06-29 10:58:58 -06001111 switch (samplerType) {
1112 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001113 case EHTokSampler1d: /*dim = Esd1D*/; break;
1114 case EHTokSampler2d: /*dim = Esd2D*/; break;
1115 case EHTokSampler3d: /*dim = Esd3D*/; break;
1116 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001117 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001118 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001119 default:
1120 return false; // not a sampler declaration
1121 }
1122
1123 advanceToken(); // consume the sampler type keyword
1124
1125 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001126
1127 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001128 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001129
1130 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1131
1132 return true;
1133}
1134
1135// texture_type
1136// | BUFFER
1137// | TEXTURE1D
1138// | TEXTURE1DARRAY
1139// | TEXTURE2D
1140// | TEXTURE2DARRAY
1141// | TEXTURE3D
1142// | TEXTURECUBE
1143// | TEXTURECUBEARRAY
1144// | TEXTURE2DMS
1145// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001146// | RWBUFFER
1147// | RWTEXTURE1D
1148// | RWTEXTURE1DARRAY
1149// | RWTEXTURE2D
1150// | RWTEXTURE2DARRAY
1151// | RWTEXTURE3D
1152
LoopDawg4886f692016-06-29 10:58:58 -06001153bool HlslGrammar::acceptTextureType(TType& type)
1154{
1155 const EHlslTokenClass textureType = peek();
1156
1157 TSamplerDim dim = EsdNone;
1158 bool array = false;
1159 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001160 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001161 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001162
1163 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001164 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001165 case EHTokTexture1d: dim = Esd1D; break;
1166 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1167 case EHTokTexture2d: dim = Esd2D; break;
1168 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1169 case EHTokTexture3d: dim = Esd3D; break;
1170 case EHTokTextureCube: dim = EsdCube; break;
1171 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1172 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1173 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1174 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1175 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1176 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1177 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1178 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1179 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001180 default:
1181 return false; // not a texture declaration
1182 }
1183
1184 advanceToken(); // consume the texture object keyword
1185
1186 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001187
LoopDawg4886f692016-06-29 10:58:58 -06001188 TIntermTyped* msCount = nullptr;
1189
steve-lunargbb0183f2016-10-04 16:58:14 -06001190 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001191 if (acceptTokenClass(EHTokLeftAngle)) {
1192 if (! acceptType(txType)) {
1193 expected("scalar or vector type");
1194 return false;
1195 }
1196
1197 const TBasicType basicRetType = txType.getBasicType() ;
1198
1199 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1200 unimplemented("basic type in texture");
1201 return false;
1202 }
1203
steve-lunargd53f7172016-07-27 15:46:48 -06001204 // Buffers can handle small mats if they fit in 4 components
1205 if (dim == EsdBuffer && txType.isMatrix()) {
1206 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1207 expected("components < 4 in matrix buffer type");
1208 return false;
1209 }
1210
1211 // TODO: except we don't handle it yet...
1212 unimplemented("matrix type in buffer");
1213 return false;
1214 }
1215
LoopDawg4886f692016-06-29 10:58:58 -06001216 if (!txType.isScalar() && !txType.isVector()) {
1217 expected("scalar or vector type");
1218 return false;
1219 }
1220
LoopDawg4886f692016-06-29 10:58:58 -06001221 if (ms && acceptTokenClass(EHTokComma)) {
1222 // read sample count for multisample types, if given
1223 if (! peekTokenClass(EHTokIntConstant)) {
1224 expected("multisample count");
1225 return false;
1226 }
1227
1228 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1229 return false;
1230 }
1231
1232 if (! acceptTokenClass(EHTokRightAngle)) {
1233 expected("right angle bracket");
1234 return false;
1235 }
1236 } else if (ms) {
1237 expected("texture type for multisample");
1238 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001239 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001240 expected("type for RWTexture/RWBuffer");
1241 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001242 }
1243
1244 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001245 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001246
1247 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001248 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001249
steve-lunarg4f2da272016-10-10 15:24:57 -06001250 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1251 if (image || dim == EsdBuffer)
1252 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001253
1254 // Non-image Buffers are combined
1255 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001256 sampler.set(txType.getBasicType(), dim, array);
1257 } else {
1258 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001259 if (image) {
1260 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1261 } else {
1262 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1263 }
steve-lunargd53f7172016-07-27 15:46:48 -06001264 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001265
1266 // Remember the declared vector size.
1267 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001268
steve-lunargbf1537f2017-03-31 17:40:09 -06001269 // Force uncombined, if necessary
1270 if (!combined)
1271 sampler.combined = false;
1272
LoopDawg4886f692016-06-29 10:58:58 -06001273 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001274 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001275
1276 return true;
1277}
1278
John Kessenich87142c72016-03-12 20:24:24 -07001279// If token is for a type, update 'type' with the type information,
1280// and return true and advance.
1281// Otherwise, return false, and don't advance
1282bool HlslGrammar::acceptType(TType& type)
1283{
John Kessenich54ee28f2017-03-11 14:13:00 -07001284 TIntermNode* nodeList = nullptr;
1285 return acceptType(type, nodeList);
1286}
1287bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1288{
steve-lunarg3226b082016-10-26 19:18:55 -06001289 // Basic types for min* types, broken out here in case of future
1290 // changes, e.g, to use native halfs.
1291 static const TBasicType min16float_bt = EbtFloat;
1292 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001293 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001294 static const TBasicType min16int_bt = EbtInt;
1295 static const TBasicType min12int_bt = EbtInt;
1296 static const TBasicType min16uint_bt = EbtUint;
1297
John Kessenich9c86c6a2016-05-03 22:49:24 -06001298 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001299 case EHTokVector:
1300 return acceptVectorTemplateType(type);
1301 break;
1302
1303 case EHTokMatrix:
1304 return acceptMatrixTemplateType(type);
1305 break;
1306
steve-lunargf49cdf42016-11-17 15:04:20 -07001307 case EHTokPointStream: // fall through
1308 case EHTokLineStream: // ...
1309 case EHTokTriangleStream: // ...
1310 {
1311 TLayoutGeometry geometry;
1312 if (! acceptStreamOutTemplateType(type, geometry))
1313 return false;
1314
1315 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1316 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001317
steve-lunargf49cdf42016-11-17 15:04:20 -07001318 return true;
1319 }
1320
steve-lunarg858c9282017-01-07 08:54:10 -07001321 case EHTokInputPatch: // fall through
1322 case EHTokOutputPatch: // ...
1323 {
1324 if (! acceptTessellationPatchTemplateType(type))
1325 return false;
1326
1327 return true;
1328 }
1329
LoopDawg4886f692016-06-29 10:58:58 -06001330 case EHTokSampler: // fall through
1331 case EHTokSampler1d: // ...
1332 case EHTokSampler2d: // ...
1333 case EHTokSampler3d: // ...
1334 case EHTokSamplerCube: // ...
1335 case EHTokSamplerState: // ...
1336 case EHTokSamplerComparisonState: // ...
1337 return acceptSamplerType(type);
1338 break;
1339
1340 case EHTokBuffer: // fall through
1341 case EHTokTexture1d: // ...
1342 case EHTokTexture1darray: // ...
1343 case EHTokTexture2d: // ...
1344 case EHTokTexture2darray: // ...
1345 case EHTokTexture3d: // ...
1346 case EHTokTextureCube: // ...
1347 case EHTokTextureCubearray: // ...
1348 case EHTokTexture2DMS: // ...
1349 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001350 case EHTokRWTexture1d: // ...
1351 case EHTokRWTexture1darray: // ...
1352 case EHTokRWTexture2d: // ...
1353 case EHTokRWTexture2darray: // ...
1354 case EHTokRWTexture3d: // ...
1355 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001356 return acceptTextureType(type);
1357 break;
1358
steve-lunarg5da1f032017-02-12 17:50:28 -07001359 case EHTokAppendStructuredBuffer:
1360 case EHTokByteAddressBuffer:
1361 case EHTokConsumeStructuredBuffer:
1362 case EHTokRWByteAddressBuffer:
1363 case EHTokRWStructuredBuffer:
1364 case EHTokStructuredBuffer:
1365 return acceptStructBufferType(type);
1366 break;
1367
steve-lunarga766b832017-04-25 09:30:28 -06001368 case EHTokConstantBuffer:
1369 return acceptConstantBufferType(type);
1370
John Kessenich27ffb292017-03-03 17:01:01 -07001371 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001372 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001373 case EHTokCBuffer:
1374 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001375 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001376
1377 case EHTokIdentifier:
1378 // An identifier could be for a user-defined type.
1379 // Note we cache the symbol table lookup, to save for a later rule
1380 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001381 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001382 advanceToken();
1383 return true;
1384 } else
1385 return false;
1386
John Kessenich71351de2016-06-08 12:50:56 -06001387 case EHTokVoid:
1388 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001389 break;
John Kessenich71351de2016-06-08 12:50:56 -06001390
John Kessenicha1e2d492016-09-20 13:22:58 -06001391 case EHTokString:
1392 new(&type) TType(EbtString);
1393 break;
1394
John Kessenich87142c72016-03-12 20:24:24 -07001395 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001396 new(&type) TType(EbtFloat);
1397 break;
John Kessenich87142c72016-03-12 20:24:24 -07001398 case EHTokFloat1:
1399 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001400 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001401 break;
John Kessenich87142c72016-03-12 20:24:24 -07001402 case EHTokFloat2:
1403 new(&type) TType(EbtFloat, EvqTemporary, 2);
1404 break;
1405 case EHTokFloat3:
1406 new(&type) TType(EbtFloat, EvqTemporary, 3);
1407 break;
1408 case EHTokFloat4:
1409 new(&type) TType(EbtFloat, EvqTemporary, 4);
1410 break;
1411
John Kessenich71351de2016-06-08 12:50:56 -06001412 case EHTokDouble:
1413 new(&type) TType(EbtDouble);
1414 break;
1415 case EHTokDouble1:
1416 new(&type) TType(EbtDouble);
1417 type.makeVector();
1418 break;
1419 case EHTokDouble2:
1420 new(&type) TType(EbtDouble, EvqTemporary, 2);
1421 break;
1422 case EHTokDouble3:
1423 new(&type) TType(EbtDouble, EvqTemporary, 3);
1424 break;
1425 case EHTokDouble4:
1426 new(&type) TType(EbtDouble, EvqTemporary, 4);
1427 break;
1428
1429 case EHTokInt:
1430 case EHTokDword:
1431 new(&type) TType(EbtInt);
1432 break;
1433 case EHTokInt1:
1434 new(&type) TType(EbtInt);
1435 type.makeVector();
1436 break;
John Kessenich87142c72016-03-12 20:24:24 -07001437 case EHTokInt2:
1438 new(&type) TType(EbtInt, EvqTemporary, 2);
1439 break;
1440 case EHTokInt3:
1441 new(&type) TType(EbtInt, EvqTemporary, 3);
1442 break;
1443 case EHTokInt4:
1444 new(&type) TType(EbtInt, EvqTemporary, 4);
1445 break;
1446
John Kessenich71351de2016-06-08 12:50:56 -06001447 case EHTokUint:
1448 new(&type) TType(EbtUint);
1449 break;
1450 case EHTokUint1:
1451 new(&type) TType(EbtUint);
1452 type.makeVector();
1453 break;
1454 case EHTokUint2:
1455 new(&type) TType(EbtUint, EvqTemporary, 2);
1456 break;
1457 case EHTokUint3:
1458 new(&type) TType(EbtUint, EvqTemporary, 3);
1459 break;
1460 case EHTokUint4:
1461 new(&type) TType(EbtUint, EvqTemporary, 4);
1462 break;
1463
1464 case EHTokBool:
1465 new(&type) TType(EbtBool);
1466 break;
1467 case EHTokBool1:
1468 new(&type) TType(EbtBool);
1469 type.makeVector();
1470 break;
John Kessenich87142c72016-03-12 20:24:24 -07001471 case EHTokBool2:
1472 new(&type) TType(EbtBool, EvqTemporary, 2);
1473 break;
1474 case EHTokBool3:
1475 new(&type) TType(EbtBool, EvqTemporary, 3);
1476 break;
1477 case EHTokBool4:
1478 new(&type) TType(EbtBool, EvqTemporary, 4);
1479 break;
1480
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001481 case EHTokHalf:
1482 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1483 break;
1484 case EHTokHalf1:
1485 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1486 type.makeVector();
1487 break;
1488 case EHTokHalf2:
1489 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1490 break;
1491 case EHTokHalf3:
1492 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1493 break;
1494 case EHTokHalf4:
1495 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1496 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001497
steve-lunarg3226b082016-10-26 19:18:55 -06001498 case EHTokMin16float:
1499 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1500 break;
1501 case EHTokMin16float1:
1502 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1503 type.makeVector();
1504 break;
1505 case EHTokMin16float2:
1506 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1507 break;
1508 case EHTokMin16float3:
1509 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1510 break;
1511 case EHTokMin16float4:
1512 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1513 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001514
steve-lunarg3226b082016-10-26 19:18:55 -06001515 case EHTokMin10float:
1516 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1517 break;
1518 case EHTokMin10float1:
1519 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1520 type.makeVector();
1521 break;
1522 case EHTokMin10float2:
1523 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1524 break;
1525 case EHTokMin10float3:
1526 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1527 break;
1528 case EHTokMin10float4:
1529 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1530 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001531
steve-lunarg3226b082016-10-26 19:18:55 -06001532 case EHTokMin16int:
1533 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1534 break;
1535 case EHTokMin16int1:
1536 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1537 type.makeVector();
1538 break;
1539 case EHTokMin16int2:
1540 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1541 break;
1542 case EHTokMin16int3:
1543 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1544 break;
1545 case EHTokMin16int4:
1546 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1547 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001548
steve-lunarg3226b082016-10-26 19:18:55 -06001549 case EHTokMin12int:
1550 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1551 break;
1552 case EHTokMin12int1:
1553 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1554 type.makeVector();
1555 break;
1556 case EHTokMin12int2:
1557 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1558 break;
1559 case EHTokMin12int3:
1560 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1561 break;
1562 case EHTokMin12int4:
1563 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1564 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001565
steve-lunarg3226b082016-10-26 19:18:55 -06001566 case EHTokMin16uint:
1567 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1568 break;
1569 case EHTokMin16uint1:
1570 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1571 type.makeVector();
1572 break;
1573 case EHTokMin16uint2:
1574 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1575 break;
1576 case EHTokMin16uint3:
1577 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1578 break;
1579 case EHTokMin16uint4:
1580 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1581 break;
1582
John Kessenich0133c122016-05-20 12:17:26 -06001583 case EHTokInt1x1:
1584 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1585 break;
1586 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001587 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001588 break;
1589 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001590 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001591 break;
1592 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001593 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001594 break;
1595 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001596 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001597 break;
1598 case EHTokInt2x2:
1599 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1600 break;
1601 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001603 break;
1604 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001605 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001606 break;
1607 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001608 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001609 break;
1610 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001611 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001612 break;
1613 case EHTokInt3x3:
1614 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1615 break;
1616 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001618 break;
1619 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001621 break;
1622 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001623 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001624 break;
1625 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001626 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001627 break;
1628 case EHTokInt4x4:
1629 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1630 break;
1631
John Kessenich71351de2016-06-08 12:50:56 -06001632 case EHTokUint1x1:
1633 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1634 break;
1635 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001636 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001637 break;
1638 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001639 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001640 break;
1641 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001642 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001643 break;
1644 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001645 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001646 break;
1647 case EHTokUint2x2:
1648 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1649 break;
1650 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001651 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001652 break;
1653 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001654 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001655 break;
1656 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001657 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001658 break;
1659 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001660 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001661 break;
1662 case EHTokUint3x3:
1663 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1664 break;
1665 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001666 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001667 break;
1668 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001669 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001670 break;
1671 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001672 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001673 break;
1674 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001675 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001676 break;
1677 case EHTokUint4x4:
1678 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1679 break;
1680
1681 case EHTokBool1x1:
1682 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1683 break;
1684 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001685 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001686 break;
1687 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001688 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001689 break;
1690 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001691 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001692 break;
1693 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001694 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001695 break;
1696 case EHTokBool2x2:
1697 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1698 break;
1699 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001700 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001701 break;
1702 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001703 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001704 break;
1705 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001706 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001707 break;
1708 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001709 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001710 break;
1711 case EHTokBool3x3:
1712 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1713 break;
1714 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001715 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001716 break;
1717 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001718 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001719 break;
1720 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001721 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001722 break;
1723 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001724 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001725 break;
1726 case EHTokBool4x4:
1727 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1728 break;
1729
John Kessenich0133c122016-05-20 12:17:26 -06001730 case EHTokFloat1x1:
1731 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1732 break;
1733 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001734 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001735 break;
1736 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001737 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001738 break;
1739 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001740 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001741 break;
1742 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001743 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001744 break;
John Kessenich87142c72016-03-12 20:24:24 -07001745 case EHTokFloat2x2:
1746 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1747 break;
1748 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001749 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001750 break;
1751 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001752 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001753 break;
John Kessenich0133c122016-05-20 12:17:26 -06001754 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001755 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001756 break;
John Kessenich87142c72016-03-12 20:24:24 -07001757 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001758 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001759 break;
1760 case EHTokFloat3x3:
1761 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1762 break;
1763 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001764 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001765 break;
John Kessenich0133c122016-05-20 12:17:26 -06001766 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001767 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001768 break;
John Kessenich87142c72016-03-12 20:24:24 -07001769 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001770 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001771 break;
1772 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001773 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001774 break;
1775 case EHTokFloat4x4:
1776 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1777 break;
1778
John Kessenich0133c122016-05-20 12:17:26 -06001779 case EHTokDouble1x1:
1780 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1781 break;
1782 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001783 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001784 break;
1785 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001786 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001787 break;
1788 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001789 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001790 break;
1791 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001792 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001793 break;
1794 case EHTokDouble2x2:
1795 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1796 break;
1797 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001798 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001799 break;
1800 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001801 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001802 break;
1803 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001804 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001805 break;
1806 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001807 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001808 break;
1809 case EHTokDouble3x3:
1810 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1811 break;
1812 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001813 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001814 break;
1815 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001816 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001817 break;
1818 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001819 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001820 break;
1821 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001822 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001823 break;
1824 case EHTokDouble4x4:
1825 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1826 break;
1827
John Kessenich87142c72016-03-12 20:24:24 -07001828 default:
1829 return false;
1830 }
1831
1832 advanceToken();
1833
1834 return true;
1835}
1836
John Kesseniche6e74942016-06-11 16:43:14 -06001837// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001838// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1839// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001840// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001841//
1842// struct_type
1843// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001844// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001845// | CBUFFER
1846// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001847//
John Kessenich54ee28f2017-03-11 14:13:00 -07001848bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001849{
John Kessenichb804de62016-09-05 12:19:18 -06001850 // This storage qualifier will tell us whether it's an AST
1851 // block type or just a generic structure type.
1852 TStorageQualifier storageQualifier = EvqTemporary;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001853 bool readonly = false;
John Kessenich3d157c52016-07-25 16:05:33 -06001854
1855 // CBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001856 if (acceptTokenClass(EHTokCBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001857 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001858 // TBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001859 } else if (acceptTokenClass(EHTokTBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001860 storageQualifier = EvqBuffer;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001861 readonly = true;
1862 }
John Kessenich27ffb292017-03-03 17:01:01 -07001863 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001864 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001865 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001866 return false;
1867
1868 // IDENTIFIER
1869 TString structName = "";
1870 if (peekTokenClass(EHTokIdentifier)) {
1871 structName = *token.string;
1872 advanceToken();
1873 }
1874
John Kessenich3d157c52016-07-25 16:05:33 -06001875 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001876 TQualifier postDeclQualifier;
1877 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001878 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001879
John Kessenichf3d88bd2017-03-19 12:24:29 -06001880 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001881 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001882 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001883 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1884 // struct_type IDENTIFIER
1885 return true;
1886 } else {
1887 expected("{");
1888 return false;
1889 }
John Kesseniche6e74942016-06-11 16:43:14 -06001890 }
1891
John Kessenichf3d88bd2017-03-19 12:24:29 -06001892
John Kesseniche6e74942016-06-11 16:43:14 -06001893 // struct_declaration_list
1894 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001895 // Save each member function so they can be processed after we have a fully formed 'this'.
1896 TVector<TFunctionDeclarator> functionDeclarators;
1897
1898 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001899 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001900 parseContext.popNamespace();
1901
1902 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001903 expected("struct member declarations");
1904 return false;
1905 }
1906
1907 // RIGHT_BRACE
1908 if (! acceptTokenClass(EHTokRightBrace)) {
1909 expected("}");
1910 return false;
1911 }
1912
1913 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001914 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001915 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001916 else {
John Kessenich7735b942016-09-05 12:40:06 -06001917 postDeclQualifier.storage = storageQualifier;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001918 postDeclQualifier.readonly = readonly;
John Kessenich7735b942016-09-05 12:40:06 -06001919 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001920 }
John Kesseniche6e74942016-06-11 16:43:14 -06001921
John Kessenich727b3742017-02-03 17:57:55 -07001922 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001923
John Kessenich4960baa2017-03-19 18:09:59 -06001924 // For member functions: now that we know the type of 'this', go back and
1925 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1926 // - parse the functions, their tokens were saved for deferred parsing (now)
1927 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1928 // update signature
1929 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001930 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001931 }
1932
John Kessenichf3d88bd2017-03-19 12:24:29 -06001933 // All member functions get parsed inside the class/struct namespace and with the
1934 // class/struct members in a symbol-table level.
1935 parseContext.pushNamespace(structName);
John Kessenich0a2a0cd2017-05-16 23:16:26 -06001936 parseContext.pushThisScope(type, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001937 bool deferredSuccess = true;
1938 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1939 // parse body
1940 pushTokenStream(functionDeclarators[b].body);
1941 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1942 deferredSuccess = false;
1943 popTokenStream();
1944 }
John Kessenich37789792017-03-21 23:56:40 -06001945 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001946 parseContext.popNamespace();
1947
1948 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001949}
1950
steve-lunarga766b832017-04-25 09:30:28 -06001951// constantbuffer
1952// : CONSTANTBUFFER LEFT_ANGLE type RIGHT_ANGLE
1953bool HlslGrammar::acceptConstantBufferType(TType& type)
1954{
1955 if (! acceptTokenClass(EHTokConstantBuffer))
1956 return false;
1957
1958 if (! acceptTokenClass(EHTokLeftAngle)) {
1959 expected("left angle bracket");
1960 return false;
1961 }
1962
1963 TType templateType;
1964 if (! acceptType(templateType)) {
1965 expected("type");
1966 return false;
1967 }
1968
1969 if (! acceptTokenClass(EHTokRightAngle)) {
1970 expected("right angle bracket");
1971 return false;
1972 }
1973
1974 TQualifier postDeclQualifier;
1975 postDeclQualifier.clear();
1976 postDeclQualifier.storage = EvqUniform;
1977
1978 if (templateType.isStruct()) {
1979 // Make a block from the type parsed as the template argument
1980 TTypeList* typeList = templateType.getWritableStruct();
1981 new(&type) TType(typeList, "", postDeclQualifier); // sets EbtBlock
1982
1983 type.getQualifier().storage = EvqUniform;
1984
1985 return true;
1986 } else {
1987 parseContext.error(token.loc, "non-structure type in ConstantBuffer", "", "");
1988 return false;
1989 }
1990}
1991
steve-lunarg5da1f032017-02-12 17:50:28 -07001992// struct_buffer
1993// : APPENDSTRUCTUREDBUFFER
1994// | BYTEADDRESSBUFFER
1995// | CONSUMESTRUCTUREDBUFFER
1996// | RWBYTEADDRESSBUFFER
1997// | RWSTRUCTUREDBUFFER
1998// | STRUCTUREDBUFFER
1999bool HlslGrammar::acceptStructBufferType(TType& type)
2000{
2001 const EHlslTokenClass structBuffType = peek();
2002
2003 // TODO: globallycoherent
2004 bool hasTemplateType = true;
2005 bool readonly = false;
2006
2007 TStorageQualifier storage = EvqBuffer;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002008 TBuiltInVariable builtinType = EbvNone;
steve-lunarg5da1f032017-02-12 17:50:28 -07002009
2010 switch (structBuffType) {
2011 case EHTokAppendStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002012 builtinType = EbvAppendConsume;
2013 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07002014 case EHTokByteAddressBuffer:
2015 hasTemplateType = false;
2016 readonly = true;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002017 builtinType = EbvByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002018 break;
2019 case EHTokConsumeStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002020 builtinType = EbvAppendConsume;
2021 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07002022 case EHTokRWByteAddressBuffer:
2023 hasTemplateType = false;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002024 builtinType = EbvRWByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002025 break;
2026 case EHTokRWStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002027 builtinType = EbvRWStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002028 break;
2029 case EHTokStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002030 builtinType = EbvStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002031 readonly = true;
2032 break;
2033 default:
2034 return false; // not a structure buffer type
2035 }
2036
2037 advanceToken(); // consume the structure keyword
2038
2039 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
2040 TType* templateType = new TType;
2041
2042 if (hasTemplateType) {
2043 if (! acceptTokenClass(EHTokLeftAngle)) {
2044 expected("left angle bracket");
2045 return false;
2046 }
2047
2048 if (! acceptType(*templateType)) {
2049 expected("type");
2050 return false;
2051 }
2052 if (! acceptTokenClass(EHTokRightAngle)) {
2053 expected("right angle bracket");
2054 return false;
2055 }
2056 } else {
2057 // byte address buffers have no explicit type.
2058 TType uintType(EbtUint, storage);
2059 templateType->shallowCopy(uintType);
2060 }
2061
2062 // Create an unsized array out of that type.
2063 // TODO: does this work if it's already an array type?
2064 TArraySizes unsizedArray;
2065 unsizedArray.addInnerSize(UnsizedArraySize);
2066 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002067 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002068
2069 // field name is canonical for all structbuffers
2070 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002071
steve-lunarg5da1f032017-02-12 17:50:28 -07002072 TTypeList* blockStruct = new TTypeList;
2073 TTypeLoc member = { templateType, token.loc };
2074 blockStruct->push_back(member);
2075
steve-lunargdd8287a2017-02-23 18:04:12 -07002076 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002077 TType blockType(blockStruct, "", templateType->getQualifier());
2078
steve-lunargdd8287a2017-02-23 18:04:12 -07002079 blockType.getQualifier().storage = storage;
2080 blockType.getQualifier().readonly = readonly;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002081 blockType.getQualifier().builtIn = builtinType;
steve-lunargdd8287a2017-02-23 18:04:12 -07002082
2083 // We may have created an equivalent type before, in which case we should use its
2084 // deep structure.
2085 parseContext.shareStructBufferType(blockType);
2086
steve-lunarg5da1f032017-02-12 17:50:28 -07002087 type.shallowCopy(blockType);
2088
2089 return true;
2090}
2091
John Kesseniche6e74942016-06-11 16:43:14 -06002092// struct_declaration_list
2093// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2094//
2095// struct_declaration
2096// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002097// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002098//
2099// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002100// : IDENTIFIER post_decls
2101// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002102// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002103//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002104bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002105 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002106{
2107 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002108 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002109
2110 do {
2111 // success on seeing the RIGHT_BRACE coming up
2112 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002113 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002114
2115 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002116
2117 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002118
2119 // fully_specified_type
2120 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002121 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002122 expected("member type");
2123 return false;
2124 }
2125
2126 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002127 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002128 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002129 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002130 expected("member name");
2131 return false;
2132 }
2133
John Kessenich54ee28f2017-03-11 14:13:00 -07002134 if (peekTokenClass(EHTokLeftParen)) {
2135 // function_parameters
2136 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002137 declarators.resize(declarators.size() + 1);
2138 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002139 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2140 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002141 if (functionDefinitionAccepted)
2142 break;
2143 }
2144 expected("member-function definition");
2145 return false;
2146 } else {
2147 // add it to the list of members
2148 TTypeLoc member = { new TType(EbtVoid), token.loc };
2149 member.type->shallowCopy(memberType);
2150 member.type->setFieldName(*idToken.string);
2151 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002152
John Kessenich54ee28f2017-03-11 14:13:00 -07002153 // array_specifier
2154 TArraySizes* arraySizes = nullptr;
2155 acceptArraySpecifier(arraySizes);
2156 if (arraySizes)
2157 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002158
John Kessenich54ee28f2017-03-11 14:13:00 -07002159 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002160
John Kessenich54ee28f2017-03-11 14:13:00 -07002161 // EQUAL assignment_expression
2162 if (acceptTokenClass(EHTokAssign)) {
2163 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2164 TIntermTyped* expressionNode = nullptr;
2165 if (! acceptAssignmentExpression(expressionNode)) {
2166 expected("initializer");
2167 return false;
2168 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002169 }
2170 }
John Kesseniche6e74942016-06-11 16:43:14 -06002171 // success on seeing the SEMICOLON coming up
2172 if (peekTokenClass(EHTokSemicolon))
2173 break;
2174
2175 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002176 if (acceptTokenClass(EHTokComma))
2177 declarator_list = true;
2178 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002179 expected(",");
2180 return false;
2181 }
2182
2183 } while (true);
2184
2185 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002186 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002187 expected(";");
2188 return false;
2189 }
2190
2191 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002192
John Kessenichb16f7e62017-03-11 19:32:47 -07002193 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002194}
2195
John Kessenich54ee28f2017-03-11 14:13:00 -07002196// member_function_definition
2197// | function_parameters post_decls compound_statement
2198//
2199// Expects type to have EvqGlobal for a static member and
2200// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002201bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2202 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002203{
John Kessenich54ee28f2017-03-11 14:13:00 -07002204 bool accepted = false;
2205
John Kessenich4dc835c2017-03-28 23:43:10 -06002206 const TString* functionName = &memberName;
2207 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002208 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002209 if (type.getQualifier().storage == EvqTemporary)
2210 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002211 else
2212 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002213
2214 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002215 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002216 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002217 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002218
2219 // compound_statement (function body definition)
2220 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002221 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002222 declarator.body = new TVector<HlslToken>;
2223 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002224 }
2225 } else
2226 expected("function parameter list");
2227
John Kessenich54ee28f2017-03-11 14:13:00 -07002228 return accepted;
2229}
2230
John Kessenich5f934b02016-03-13 17:58:25 -06002231// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002232// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002233// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002234//
2235bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2236{
John Kessenich078d7f22016-03-14 10:02:11 -06002237 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002238 if (! acceptTokenClass(EHTokLeftParen))
2239 return false;
2240
John Kessenich71351de2016-06-08 12:50:56 -06002241 // VOID RIGHT_PAREN
2242 if (! acceptTokenClass(EHTokVoid)) {
2243 do {
2244 // parameter_declaration
2245 if (! acceptParameterDeclaration(function))
2246 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002247
John Kessenich71351de2016-06-08 12:50:56 -06002248 // COMMA
2249 if (! acceptTokenClass(EHTokComma))
2250 break;
2251 } while (true);
2252 }
John Kessenich5f934b02016-03-13 17:58:25 -06002253
John Kessenich078d7f22016-03-14 10:02:11 -06002254 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002255 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002256 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002257 return false;
2258 }
2259
2260 return true;
2261}
2262
steve-lunarg26d31452016-12-23 18:56:57 -07002263// default_parameter_declaration
2264// : EQUAL conditional_expression
2265// : EQUAL initializer
2266bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2267{
2268 node = nullptr;
2269
2270 // Valid not to have a default_parameter_declaration
2271 if (!acceptTokenClass(EHTokAssign))
2272 return true;
2273
2274 if (!acceptConditionalExpression(node)) {
2275 if (!acceptInitializer(node))
2276 return false;
2277
2278 // For initializer lists, we have to const-fold into a constructor for the type, so build
2279 // that.
John Kessenichc633f642017-04-03 21:48:37 -06002280 TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
steve-lunarg26d31452016-12-23 18:56:57 -07002281 if (constructor == nullptr) // cannot construct
2282 return false;
2283
2284 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002285 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002286 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002287
steve-lunarg26d31452016-12-23 18:56:57 -07002288 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2289 }
2290
2291 // If this is simply a constant, we can use it directly.
2292 if (node->getAsConstantUnion())
2293 return true;
2294
2295 // Otherwise, it has to be const-foldable.
2296 TIntermTyped* origNode = node;
2297
2298 node = intermediate.fold(node->getAsAggregate());
2299
2300 if (node != nullptr && origNode != node)
2301 return true;
2302
2303 parseContext.error(token.loc, "invalid default parameter value", "", "");
2304
2305 return false;
2306}
2307
John Kessenich5f934b02016-03-13 17:58:25 -06002308// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002309// : fully_specified_type post_decls [ = default_parameter_declaration ]
2310// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002311//
2312bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2313{
2314 // fully_specified_type
2315 TType* type = new TType;
2316 if (! acceptFullySpecifiedType(*type))
2317 return false;
2318
2319 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002320 HlslToken idToken;
2321 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002322
John Kessenich19b92ff2016-06-19 11:50:34 -06002323 // array_specifier
2324 TArraySizes* arraySizes = nullptr;
2325 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002326 if (arraySizes) {
2327 if (arraySizes->isImplicit()) {
2328 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2329 return false;
2330 }
2331
John Kessenich19b92ff2016-06-19 11:50:34 -06002332 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002333 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002334
2335 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002336 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002337
steve-lunarg26d31452016-12-23 18:56:57 -07002338 TIntermTyped* defaultValue;
2339 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2340 return false;
2341
John Kessenich5aa59e22016-06-17 15:50:47 -06002342 parseContext.paramFix(*type);
2343
steve-lunarg26d31452016-12-23 18:56:57 -07002344 // If any prior parameters have default values, all the parameters after that must as well.
2345 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2346 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2347 return false;
2348 }
2349
2350 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002351 function.addParameter(param);
2352
2353 return true;
2354}
2355
2356// Do the work to create the function definition in addition to
2357// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002358//
2359// If 'deferredTokens' are passed in, just get the token stream,
2360// don't process.
2361//
2362bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2363 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002364{
John Kessenich088d52b2017-03-11 17:55:28 -07002365 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002366
John Kessenichb16f7e62017-03-11 19:32:47 -07002367 if (deferredTokens)
2368 return captureBlockTokens(*deferredTokens);
2369 else
John Kessenich4960baa2017-03-19 18:09:59 -06002370 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002371}
2372
2373bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2374{
2375 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002376 TIntermNode* entryPointNode = nullptr;
2377
John Kessenich077e0522016-06-09 02:02:17 -06002378 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002379 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2380 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002381
2382 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002383 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002384 if (! acceptCompoundStatement(functionBody))
2385 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002386
John Kessenich54ee28f2017-03-11 14:13:00 -07002387 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002388 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002389
2390 // Hook up the 1 or 2 function definitions.
2391 nodeList = intermediate.growAggregate(nodeList, functionNode);
2392 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002393
2394 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002395}
2396
John Kessenich0d2b6de2016-06-05 11:23:11 -06002397// Accept an expression with parenthesis around it, where
2398// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002399// syntactically required ones like in "if ( expression )".
2400//
2401// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002402//
2403// Note this one is not set up to be speculative; as it gives
2404// errors if not found.
2405//
2406bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2407{
2408 // LEFT_PAREN
2409 if (! acceptTokenClass(EHTokLeftParen))
2410 expected("(");
2411
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002412 bool decl = false;
2413 TIntermNode* declNode = nullptr;
2414 decl = acceptControlDeclaration(declNode);
2415 if (decl) {
2416 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2417 expected("initialized declaration");
2418 return false;
2419 } else
2420 expression = declNode->getAsTyped();
2421 } else {
2422 // no declaration
2423 if (! acceptExpression(expression)) {
2424 expected("expression");
2425 return false;
2426 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002427 }
2428
2429 // RIGHT_PAREN
2430 if (! acceptTokenClass(EHTokRightParen))
2431 expected(")");
2432
2433 return true;
2434}
2435
John Kessenich34fb0362016-05-03 23:17:20 -06002436// The top-level full expression recognizer.
2437//
John Kessenich87142c72016-03-12 20:24:24 -07002438// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002439// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002440//
2441bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2442{
LoopDawgef764a22016-06-03 09:17:51 -06002443 node = nullptr;
2444
John Kessenich34fb0362016-05-03 23:17:20 -06002445 // assignment_expression
2446 if (! acceptAssignmentExpression(node))
2447 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002448
John Kessenich34fb0362016-05-03 23:17:20 -06002449 if (! peekTokenClass(EHTokComma))
2450 return true;
2451
2452 do {
2453 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002454 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002455 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002456
John Kessenich34fb0362016-05-03 23:17:20 -06002457 // ... assignment_expression
2458 TIntermTyped* rightNode = nullptr;
2459 if (! acceptAssignmentExpression(rightNode)) {
2460 expected("assignment expression");
2461 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002462 }
2463
John Kessenich34fb0362016-05-03 23:17:20 -06002464 node = intermediate.addComma(node, rightNode, loc);
2465
2466 if (! peekTokenClass(EHTokComma))
2467 return true;
2468 } while (true);
2469}
2470
John Kessenich07354242016-07-01 19:58:06 -06002471// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002472// : LEFT_BRACE RIGHT_BRACE
2473// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002474//
2475// initializer_list
2476// : assignment_expression COMMA assignment_expression COMMA ...
2477//
2478bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2479{
2480 // LEFT_BRACE
2481 if (! acceptTokenClass(EHTokLeftBrace))
2482 return false;
2483
John Kessenich98ad4852016-11-27 17:39:07 -07002484 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002485 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002486 if (acceptTokenClass(EHTokRightBrace)) {
2487 // a zero-length initializer list
2488 node = intermediate.makeAggregate(loc);
2489 return true;
2490 }
2491
2492 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002493 node = nullptr;
2494 do {
2495 // assignment_expression
2496 TIntermTyped* expr;
2497 if (! acceptAssignmentExpression(expr)) {
2498 expected("assignment expression in initializer list");
2499 return false;
2500 }
2501 node = intermediate.growAggregate(node, expr, loc);
2502
2503 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002504 if (acceptTokenClass(EHTokComma)) {
2505 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2506 return true;
John Kessenich07354242016-07-01 19:58:06 -06002507 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002508 }
John Kessenich07354242016-07-01 19:58:06 -06002509
2510 // RIGHT_BRACE
2511 if (acceptTokenClass(EHTokRightBrace))
2512 return true;
2513
2514 expected(", or }");
2515 return false;
2516 } while (true);
2517}
2518
John Kessenich34fb0362016-05-03 23:17:20 -06002519// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002520// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002521//
2522// a op (b op (c op d))
2523//
2524// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002525// : initializer
2526// | conditional_expression
2527// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002528//
2529bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2530{
John Kessenich07354242016-07-01 19:58:06 -06002531 // initializer
2532 if (peekTokenClass(EHTokLeftBrace)) {
2533 if (acceptInitializer(node))
2534 return true;
2535
2536 expected("initializer");
2537 return false;
2538 }
2539
John Kessenich00957f82016-07-27 10:39:57 -06002540 // conditional_expression
2541 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002542 return false;
2543
John Kessenich07354242016-07-01 19:58:06 -06002544 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002545 TOperator assignOp = HlslOpMap::assignment(peek());
2546 if (assignOp == EOpNull)
2547 return true;
2548
John Kessenich00957f82016-07-27 10:39:57 -06002549 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002550 TSourceLoc loc = token.loc;
2551 advanceToken();
2552
John Kessenich00957f82016-07-27 10:39:57 -06002553 // conditional_expression assign_op conditional_expression ...
2554 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002555 // gets the right-to-left associativity.
2556 TIntermTyped* rightNode = nullptr;
2557 if (! acceptAssignmentExpression(rightNode)) {
2558 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002559 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002560 }
2561
John Kessenichd21baed2016-09-16 03:05:12 -06002562 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002563 node = parseContext.handleLvalue(loc, "assign", node);
2564
John Kessenichfea226b2016-07-28 17:53:56 -06002565 if (node == nullptr) {
2566 parseContext.error(loc, "could not create assignment", "", "");
2567 return false;
2568 }
John Kessenich34fb0362016-05-03 23:17:20 -06002569
2570 if (! peekTokenClass(EHTokComma))
2571 return true;
2572
2573 return true;
2574}
2575
John Kessenich00957f82016-07-27 10:39:57 -06002576// Accept a conditional expression, which associates right-to-left,
2577// accomplished by the "true" expression calling down to lower
2578// precedence levels than this level.
2579//
2580// conditional_expression
2581// : binary_expression
2582// | binary_expression QUESTION expression COLON assignment_expression
2583//
2584bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2585{
2586 // binary_expression
2587 if (! acceptBinaryExpression(node, PlLogicalOr))
2588 return false;
2589
2590 if (! acceptTokenClass(EHTokQuestion))
2591 return true;
2592
John Kessenich636b62d2017-04-11 19:45:00 -06002593 node = parseContext.convertConditionalExpression(token.loc, node, false);
John Kessenich7e997e22017-03-30 22:09:30 -06002594 if (node == nullptr)
2595 return false;
2596
John Kessenich00957f82016-07-27 10:39:57 -06002597 TIntermTyped* trueNode = nullptr;
2598 if (! acceptExpression(trueNode)) {
2599 expected("expression after ?");
2600 return false;
2601 }
2602 TSourceLoc loc = token.loc;
2603
2604 if (! acceptTokenClass(EHTokColon)) {
2605 expected(":");
2606 return false;
2607 }
2608
2609 TIntermTyped* falseNode = nullptr;
2610 if (! acceptAssignmentExpression(falseNode)) {
2611 expected("expression after :");
2612 return false;
2613 }
2614
2615 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2616
2617 return true;
2618}
2619
John Kessenich34fb0362016-05-03 23:17:20 -06002620// Accept a binary expression, for binary operations that
2621// associate left-to-right. This is, it is implicit, for example
2622//
2623// ((a op b) op c) op d
2624//
2625// binary_expression
2626// : expression op expression op expression ...
2627//
2628// where 'expression' is the next higher level in precedence.
2629//
2630bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2631{
2632 if (precedenceLevel > PlMul)
2633 return acceptUnaryExpression(node);
2634
2635 // assignment_expression
2636 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2637 return false;
2638
John Kessenich34fb0362016-05-03 23:17:20 -06002639 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002640 TOperator op = HlslOpMap::binary(peek());
2641 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2642 if (tokenLevel < precedenceLevel)
2643 return true;
2644
John Kessenich34fb0362016-05-03 23:17:20 -06002645 // ... op
2646 TSourceLoc loc = token.loc;
2647 advanceToken();
2648
2649 // ... expression
2650 TIntermTyped* rightNode = nullptr;
2651 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2652 expected("expression");
2653 return false;
2654 }
2655
2656 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002657 if (node == nullptr) {
2658 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2659 return false;
2660 }
John Kessenich34fb0362016-05-03 23:17:20 -06002661 } while (true);
2662}
2663
2664// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002665// : (type) unary_expression
2666// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002667// | - unary_expression
2668// | ! unary_expression
2669// | ~ unary_expression
2670// | ++ unary_expression
2671// | -- unary_expression
2672// | postfix_expression
2673//
2674bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2675{
John Kessenich1cc1a282016-06-03 16:55:49 -06002676 // (type) unary_expression
2677 // Have to look two steps ahead, because this could be, e.g., a
2678 // postfix_expression instead, since that also starts with at "(".
2679 if (acceptTokenClass(EHTokLeftParen)) {
2680 TType castType;
2681 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002682 if (acceptTokenClass(EHTokRightParen)) {
2683 // We've matched "(type)" now, get the expression to cast
2684 TSourceLoc loc = token.loc;
2685 if (! acceptUnaryExpression(node))
2686 return false;
2687
2688 // Hook it up like a constructor
John Kessenichc633f642017-04-03 21:48:37 -06002689 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
steve-lunarg5964c642016-07-30 07:38:55 -06002690 if (constructorFunction == nullptr) {
2691 expected("type that can be constructed");
2692 return false;
2693 }
2694 TIntermTyped* arguments = nullptr;
2695 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2696 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2697
2698 return true;
2699 } else {
2700 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2701 // the '(int' part. We must back up twice.
2702 recedeToken();
2703 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002704 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002705 } else {
2706 // This isn't a type cast, but it still started "(", so if it is a
2707 // unary expression, it can only be a postfix_expression, so try that.
2708 // Back it up first.
2709 recedeToken();
2710 return acceptPostfixExpression(node);
2711 }
2712 }
2713
2714 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002715 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002716
John Kessenich1cc1a282016-06-03 16:55:49 -06002717 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002718 if (unaryOp == EOpNull)
2719 return acceptPostfixExpression(node);
2720
2721 // op unary_expression
2722 TSourceLoc loc = token.loc;
2723 advanceToken();
2724 if (! acceptUnaryExpression(node))
2725 return false;
2726
2727 // + is a no-op
2728 if (unaryOp == EOpAdd)
2729 return true;
2730
2731 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002732
2733 // These unary ops require lvalues
2734 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2735 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002736
2737 return node != nullptr;
2738}
2739
2740// postfix_expression
2741// : LEFT_PAREN expression RIGHT_PAREN
2742// | literal
2743// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002744// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002745// | function_call
2746// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2747// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002748// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002749// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002750// | postfix_expression INC_OP
2751// | postfix_expression DEC_OP
2752//
2753bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2754{
2755 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002756 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002757
2758 // idToken will pick up either a variable or a function name in a function call
2759 HlslToken idToken;
2760
John Kessenich21472ae2016-06-04 11:46:33 -06002761 // Find something before the postfix operations, as they can't operate
2762 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002763 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002764 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002765 if (! acceptExpression(node)) {
2766 expected("expression");
2767 return false;
2768 }
2769 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002770 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002771 return false;
2772 }
John Kessenich34fb0362016-05-03 23:17:20 -06002773 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002774 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002775 } else if (acceptConstructor(node)) {
2776 // constructor (nothing else to do yet)
2777 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002778 // user-type, namespace name, variable, or function name
2779 TString* fullName = idToken.string;
2780 while (acceptTokenClass(EHTokColonColon)) {
2781 // user-type or namespace name
2782 fullName = NewPoolTString(fullName->c_str());
2783 fullName->append(parseContext.scopeMangler);
2784 if (acceptIdentifier(idToken))
2785 fullName->append(*idToken.string);
2786 else {
2787 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002788 return false;
2789 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002790 }
2791 if (! peekTokenClass(EHTokLeftParen)) {
2792 node = parseContext.handleVariable(idToken.loc, fullName);
2793 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002794 // function_call (nothing else to do yet)
2795 } else {
2796 expected("function call arguments");
2797 return false;
2798 }
John Kessenich21472ae2016-06-04 11:46:33 -06002799 } else {
2800 // nothing found, can't post operate
2801 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002802 }
2803
steve-lunarga2b01a02016-11-28 17:09:54 -07002804 // This is to guarantee we do this no matter how we get out of the stack frame.
2805 // This way there's no bug if an early return forgets to do it.
2806 struct tFinalize {
2807 tFinalize(HlslParseContext& p) : parseContext(p) { }
2808 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002809 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002810 private:
John Kessenichca71d942017-03-07 20:44:09 -07002811 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002812 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002813 } finalize(parseContext);
2814
2815 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2816 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2817 // level: hence the init and finalize. Even though in practice these must be
2818 // constants, they are parsed no matter what.
2819 parseContext.initFlattening();
2820
John Kessenich21472ae2016-06-04 11:46:33 -06002821 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002822 do {
2823 TSourceLoc loc = token.loc;
2824 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002825
John Kessenich34fb0362016-05-03 23:17:20 -06002826 // Consume only a valid post-unary operator, otherwise we are done.
2827 switch (postOp) {
2828 case EOpIndexDirectStruct:
2829 case EOpIndexIndirect:
2830 case EOpPostIncrement:
2831 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002832 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002833 advanceToken();
2834 break;
2835 default:
2836 return true;
2837 }
John Kessenich87142c72016-03-12 20:24:24 -07002838
John Kessenich34fb0362016-05-03 23:17:20 -06002839 // We have a valid post-unary operator, process it.
2840 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002841 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002842 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002843 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002844 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002845 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002846 HlslToken field;
2847 if (! acceptIdentifier(field)) {
2848 expected("swizzle or member");
2849 return false;
2850 }
LoopDawg4886f692016-06-29 10:58:58 -06002851
John Kessenich516d92d2017-03-08 20:09:03 -07002852 if (peekTokenClass(EHTokLeftParen)) {
2853 // member function
2854 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002855
John Kessenich516d92d2017-03-08 20:09:03 -07002856 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002857 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002858 expected("function parameters");
2859 return false;
2860 }
John Kessenich516d92d2017-03-08 20:09:03 -07002861 } else
2862 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002863
John Kessenich34fb0362016-05-03 23:17:20 -06002864 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002865 }
John Kessenich34fb0362016-05-03 23:17:20 -06002866 case EOpIndexIndirect:
2867 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002868 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002869 TIntermTyped* indexNode = nullptr;
2870 if (! acceptExpression(indexNode) ||
2871 ! peekTokenClass(EHTokRightBracket)) {
2872 expected("expression followed by ']'");
2873 return false;
2874 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002875 advanceToken();
2876 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
steve-lunarg2efd6c62017-04-06 20:22:20 -06002877 if (node == nullptr)
2878 return false;
John Kessenich19b92ff2016-06-19 11:50:34 -06002879 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002880 }
2881 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002882 // INC_OP
2883 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002884 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002885 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002886 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002887 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002888 break;
2889 default:
2890 assert(0);
2891 break;
2892 }
2893 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002894}
2895
John Kessenichd016be12016-03-13 11:24:20 -06002896// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002897// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002898//
2899bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2900{
2901 // type
2902 TType type;
2903 if (acceptType(type)) {
John Kessenichc633f642017-04-03 21:48:37 -06002904 TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
John Kessenichd016be12016-03-13 11:24:20 -06002905 if (constructorFunction == nullptr)
2906 return false;
2907
2908 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002909 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002910 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002911 // It's possible this is a type keyword used as an identifier. Put the token back
2912 // for later use.
2913 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002914 return false;
2915 }
2916
2917 // hook it up
2918 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2919
2920 return true;
2921 }
2922
2923 return false;
2924}
2925
John Kessenich34fb0362016-05-03 23:17:20 -06002926// The function_call identifier was already recognized, and passed in as idToken.
2927//
2928// function_call
2929// : [idToken] arguments
2930//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002931bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002932{
John Kessenich54ee28f2017-03-11 14:13:00 -07002933 // name
2934 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002935 if (baseObject == nullptr) {
2936 functionName = &name;
2937 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002938 // Built-in methods are not in the symbol table as methods, but as global functions
2939 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002940 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002941 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002942 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002943 if (! baseObject->getType().isStruct()) {
2944 expected("structure");
2945 return false;
2946 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002947 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002948 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002949 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002950 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002951 }
LoopDawg4886f692016-06-29 10:58:58 -06002952
John Kessenich54ee28f2017-03-11 14:13:00 -07002953 // function
2954 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2955
2956 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002957 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002958 if (baseObject != nullptr) {
2959 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002960 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002961 }
John Kessenich4678ca92016-05-13 09:33:42 -06002962 if (! acceptArguments(function, arguments))
2963 return false;
2964
John Kessenich54ee28f2017-03-11 14:13:00 -07002965 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002966 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002967
2968 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002969}
2970
John Kessenich87142c72016-03-12 20:24:24 -07002971// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002972// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002973//
John Kessenichd016be12016-03-13 11:24:20 -06002974// The arguments are pushed onto the 'function' argument list and
2975// onto the 'arguments' aggregate.
2976//
John Kessenich4678ca92016-05-13 09:33:42 -06002977bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002978{
John Kessenich078d7f22016-03-14 10:02:11 -06002979 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002980 if (! acceptTokenClass(EHTokLeftParen))
2981 return false;
2982
John Kessenich2aa12b12017-04-18 14:47:33 -06002983 // RIGHT_PAREN
2984 if (acceptTokenClass(EHTokRightParen))
2985 return true;
2986
2987 // must now be at least one expression...
John Kessenich87142c72016-03-12 20:24:24 -07002988 do {
John Kessenichd016be12016-03-13 11:24:20 -06002989 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002990 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002991 if (! acceptAssignmentExpression(arg))
John Kessenich2aa12b12017-04-18 14:47:33 -06002992 return false;
John Kessenichd016be12016-03-13 11:24:20 -06002993
2994 // hook it up
2995 parseContext.handleFunctionArgument(function, arguments, arg);
2996
John Kessenich078d7f22016-03-14 10:02:11 -06002997 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002998 if (! acceptTokenClass(EHTokComma))
2999 break;
3000 } while (true);
3001
John Kessenich078d7f22016-03-14 10:02:11 -06003002 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07003003 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003004 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07003005 return false;
3006 }
3007
3008 return true;
3009}
3010
3011bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
3012{
3013 switch (token.tokenClass) {
3014 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003015 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003016 break;
steve-lunarg2de32912016-07-28 14:49:48 -06003017 case EHTokUintConstant:
3018 node = intermediate.addConstantUnion(token.u, token.loc, true);
3019 break;
John Kessenich87142c72016-03-12 20:24:24 -07003020 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003021 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003022 break;
3023 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003024 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003025 break;
3026 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003027 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003028 break;
John Kessenich86f71382016-09-19 20:23:18 -06003029 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07003030 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06003031 break;
John Kessenich87142c72016-03-12 20:24:24 -07003032
3033 default:
3034 return false;
3035 }
3036
3037 advanceToken();
3038
3039 return true;
3040}
3041
John Kessenich0e071192017-06-06 11:37:33 -06003042// simple_statement
3043// : SEMICOLON
3044// | declaration_statement
3045// | expression SEMICOLON
3046//
3047bool HlslGrammar::acceptSimpleStatement(TIntermNode*& statement)
3048{
3049 // SEMICOLON
3050 if (acceptTokenClass(EHTokSemicolon))
3051 return true;
3052
3053 // declaration
3054 if (acceptDeclaration(statement))
3055 return true;
3056
3057 // expression
3058 TIntermTyped* node;
3059 if (acceptExpression(node))
3060 statement = node;
3061 else
3062 return false;
3063
3064 // SEMICOLON (following an expression)
3065 if (acceptTokenClass(EHTokSemicolon))
3066 return true;
3067 else {
3068 expected(";");
3069 return false;
3070 }
3071}
3072
John Kessenich5f934b02016-03-13 17:58:25 -06003073// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06003074// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003075//
John Kessenich21472ae2016-06-04 11:46:33 -06003076bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07003077{
John Kessenich21472ae2016-06-04 11:46:33 -06003078 TIntermAggregate* compoundStatement = nullptr;
3079
John Kessenich34fb0362016-05-03 23:17:20 -06003080 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003081 if (! acceptTokenClass(EHTokLeftBrace))
3082 return false;
3083
3084 // statement statement ...
3085 TIntermNode* statement = nullptr;
3086 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06003087 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
3088 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
3089 branch->getFlowOp() == EOpDefault)) {
3090 // hook up individual subsequences within a switch statement
3091 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
3092 compoundStatement = nullptr;
3093 } else {
3094 // hook it up to the growing compound statement
3095 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3096 }
John Kessenich5f934b02016-03-13 17:58:25 -06003097 }
John Kessenich34fb0362016-05-03 23:17:20 -06003098 if (compoundStatement)
3099 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06003100
John Kessenich21472ae2016-06-04 11:46:33 -06003101 retStatement = compoundStatement;
3102
John Kessenich34fb0362016-05-03 23:17:20 -06003103 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003104 return acceptTokenClass(EHTokRightBrace);
3105}
3106
John Kessenich0d2b6de2016-06-05 11:23:11 -06003107bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3108{
3109 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003110 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003111 parseContext.popScope();
3112
3113 return result;
3114}
3115
John Kessenich077e0522016-06-09 02:02:17 -06003116bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003117{
John Kessenich077e0522016-06-09 02:02:17 -06003118 parseContext.pushScope();
3119 bool result = acceptCompoundStatement(statement);
3120 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003121
3122 return result;
3123}
3124
John Kessenich5f934b02016-03-13 17:58:25 -06003125// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003126// : attributes attributed_statement
3127//
3128// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003129// : compound_statement
John Kessenich0e071192017-06-06 11:37:33 -06003130// | simple_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003131// | selection_statement
3132// | switch_statement
3133// | case_label
John Kessenich0e071192017-06-06 11:37:33 -06003134// | default_label
John Kessenich21472ae2016-06-04 11:46:33 -06003135// | iteration_statement
3136// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003137//
3138bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3139{
John Kessenich21472ae2016-06-04 11:46:33 -06003140 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003141
John Kessenich21472ae2016-06-04 11:46:33 -06003142 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003143 TAttributeMap attributes;
3144 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003145
John Kessenich21472ae2016-06-04 11:46:33 -06003146 // attributed_statement
3147 switch (peek()) {
3148 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003149 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003150
John Kessenich21472ae2016-06-04 11:46:33 -06003151 case EHTokIf:
3152 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003153
John Kessenich21472ae2016-06-04 11:46:33 -06003154 case EHTokSwitch:
3155 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003156
John Kessenich21472ae2016-06-04 11:46:33 -06003157 case EHTokFor:
3158 case EHTokDo:
3159 case EHTokWhile:
steve-lunargf1709e72017-05-02 20:14:50 -06003160 return acceptIterationStatement(statement, attributes);
John Kessenich21472ae2016-06-04 11:46:33 -06003161
3162 case EHTokContinue:
3163 case EHTokBreak:
3164 case EHTokDiscard:
3165 case EHTokReturn:
3166 return acceptJumpStatement(statement);
3167
3168 case EHTokCase:
3169 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003170 case EHTokDefault:
3171 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003172
John Kessenich21472ae2016-06-04 11:46:33 -06003173 case EHTokRightBrace:
3174 // Performance: not strictly necessary, but stops a bunch of hunting early,
3175 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003176 return false;
3177
John Kessenich21472ae2016-06-04 11:46:33 -06003178 default:
John Kessenich0e071192017-06-06 11:37:33 -06003179 return acceptSimpleStatement(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003180 }
3181
John Kessenich5f934b02016-03-13 17:58:25 -06003182 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003183}
3184
John Kessenich21472ae2016-06-04 11:46:33 -06003185// attributes
3186// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3187//
3188// attribute:
3189// : UNROLL
3190// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3191// | FASTOPT
3192// | ALLOW_UAV_CONDITION
3193// | BRANCH
3194// | FLATTEN
3195// | FORCECASE
3196// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003197// | DOMAIN
3198// | EARLYDEPTHSTENCIL
3199// | INSTANCE
3200// | MAXTESSFACTOR
3201// | OUTPUTCONTROLPOINTS
3202// | OUTPUTTOPOLOGY
3203// | PARTITIONING
3204// | PATCHCONSTANTFUNC
3205// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003206//
steve-lunarg1868b142016-10-20 13:07:10 -06003207void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003208{
steve-lunarg1868b142016-10-20 13:07:10 -06003209 // For now, accept the [ XXX(X) ] syntax, but drop all but
3210 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003211 // TODO: subset to correct set? Pass on?
3212 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003213 HlslToken idToken;
3214
John Kessenich0d2b6de2016-06-05 11:23:11 -06003215 // LEFT_BRACKET?
3216 if (! acceptTokenClass(EHTokLeftBracket))
3217 return;
3218
3219 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003220 if (acceptIdentifier(idToken)) {
3221 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003222 } else if (! peekTokenClass(EHTokRightBracket)) {
3223 expected("identifier");
3224 advanceToken();
3225 }
3226
steve-lunarga22f7db2016-11-11 08:17:44 -07003227 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003228
3229 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003230 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003231 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003232
John Kessenich0d2b6de2016-06-05 11:23:11 -06003233 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003234 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003235
steve-lunarga22f7db2016-11-11 08:17:44 -07003236 while (acceptAssignmentExpression(node)) {
3237 expectingExpression = false;
3238 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003239 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003240 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003241 }
3242
steve-lunarga22f7db2016-11-11 08:17:44 -07003243 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003244 if (! acceptTokenClass(EHTokRightParen))
3245 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003246
3247 // Error for partial or missing expression
3248 if (expectingExpression || expressions->getSequence().empty())
3249 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003250 }
3251
3252 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003253 if (!acceptTokenClass(EHTokRightBracket)) {
3254 expected("]");
3255 return;
3256 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003257
steve-lunarg1868b142016-10-20 13:07:10 -06003258 // Add any values we found into the attribute map. This accepts
3259 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003260 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003261 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003262}
3263
John Kessenich0d2b6de2016-06-05 11:23:11 -06003264// selection_statement
3265// : IF LEFT_PAREN expression RIGHT_PAREN statement
3266// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3267//
John Kessenich21472ae2016-06-04 11:46:33 -06003268bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3269{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003270 TSourceLoc loc = token.loc;
3271
3272 // IF
3273 if (! acceptTokenClass(EHTokIf))
3274 return false;
3275
3276 // so that something declared in the condition is scoped to the lifetimes
3277 // of the then-else statements
3278 parseContext.pushScope();
3279
3280 // LEFT_PAREN expression RIGHT_PAREN
3281 TIntermTyped* condition;
3282 if (! acceptParenExpression(condition))
3283 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003284 condition = parseContext.convertConditionalExpression(loc, condition);
3285 if (condition == nullptr)
3286 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003287
3288 // create the child statements
3289 TIntermNodePair thenElse = { nullptr, nullptr };
3290
3291 // then statement
3292 if (! acceptScopedStatement(thenElse.node1)) {
3293 expected("then statement");
3294 return false;
3295 }
3296
3297 // ELSE
3298 if (acceptTokenClass(EHTokElse)) {
3299 // else statement
3300 if (! acceptScopedStatement(thenElse.node2)) {
3301 expected("else statement");
3302 return false;
3303 }
3304 }
3305
3306 // Put the pieces together
3307 statement = intermediate.addSelection(condition, thenElse, loc);
3308 parseContext.popScope();
3309
3310 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003311}
3312
John Kessenichd02dc5d2016-07-01 00:04:11 -06003313// switch_statement
3314// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3315//
John Kessenich21472ae2016-06-04 11:46:33 -06003316bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3317{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003318 // SWITCH
3319 TSourceLoc loc = token.loc;
3320 if (! acceptTokenClass(EHTokSwitch))
3321 return false;
3322
3323 // LEFT_PAREN expression RIGHT_PAREN
3324 parseContext.pushScope();
3325 TIntermTyped* switchExpression;
3326 if (! acceptParenExpression(switchExpression)) {
3327 parseContext.popScope();
3328 return false;
3329 }
3330
3331 // compound_statement
3332 parseContext.pushSwitchSequence(new TIntermSequence);
3333 bool statementOkay = acceptCompoundStatement(statement);
3334 if (statementOkay)
3335 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3336
3337 parseContext.popSwitchSequence();
3338 parseContext.popScope();
3339
3340 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003341}
3342
John Kessenich119f8f62016-06-05 15:44:07 -06003343// iteration_statement
3344// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3345// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3346// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3347//
3348// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
steve-lunargf1709e72017-05-02 20:14:50 -06003349bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003350{
John Kessenich119f8f62016-06-05 15:44:07 -06003351 TSourceLoc loc = token.loc;
3352 TIntermTyped* condition = nullptr;
3353
3354 EHlslTokenClass loop = peek();
3355 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3356
3357 // WHILE or DO or FOR
3358 advanceToken();
steve-lunargf1709e72017-05-02 20:14:50 -06003359
3360 const TLoopControl control = parseContext.handleLoopControl(attributes);
John Kessenich119f8f62016-06-05 15:44:07 -06003361
3362 switch (loop) {
3363 case EHTokWhile:
3364 // so that something declared in the condition is scoped to the lifetime
3365 // of the while sub-statement
3366 parseContext.pushScope();
3367 parseContext.nestLooping();
3368
3369 // LEFT_PAREN condition RIGHT_PAREN
3370 if (! acceptParenExpression(condition))
3371 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003372 condition = parseContext.convertConditionalExpression(loc, condition);
3373 if (condition == nullptr)
3374 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003375
3376 // statement
3377 if (! acceptScopedStatement(statement)) {
3378 expected("while sub-statement");
3379 return false;
3380 }
3381
3382 parseContext.unnestLooping();
3383 parseContext.popScope();
3384
steve-lunargf1709e72017-05-02 20:14:50 -06003385 statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003386
3387 return true;
3388
3389 case EHTokDo:
3390 parseContext.nestLooping();
3391
John Kessenich119f8f62016-06-05 15:44:07 -06003392 // statement
John Kessenich0c6f9362017-04-20 11:08:24 -06003393 if (! acceptScopedStatement(statement)) {
John Kessenich119f8f62016-06-05 15:44:07 -06003394 expected("do sub-statement");
3395 return false;
3396 }
3397
John Kessenich119f8f62016-06-05 15:44:07 -06003398 // WHILE
3399 if (! acceptTokenClass(EHTokWhile)) {
3400 expected("while");
3401 return false;
3402 }
3403
3404 // LEFT_PAREN condition RIGHT_PAREN
3405 TIntermTyped* condition;
3406 if (! acceptParenExpression(condition))
3407 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003408 condition = parseContext.convertConditionalExpression(loc, condition);
3409 if (condition == nullptr)
3410 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003411
3412 if (! acceptTokenClass(EHTokSemicolon))
3413 expected(";");
3414
3415 parseContext.unnestLooping();
3416
steve-lunargf1709e72017-05-02 20:14:50 -06003417 statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003418
3419 return true;
3420
3421 case EHTokFor:
3422 {
3423 // LEFT_PAREN
3424 if (! acceptTokenClass(EHTokLeftParen))
3425 expected("(");
3426
3427 // so that something declared in the condition is scoped to the lifetime
3428 // of the for sub-statement
3429 parseContext.pushScope();
3430
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003431 // initializer
3432 TIntermNode* initNode = nullptr;
John Kessenich0e071192017-06-06 11:37:33 -06003433 if (! acceptSimpleStatement(initNode))
3434 expected("for-loop initializer statement");
John Kessenich119f8f62016-06-05 15:44:07 -06003435
3436 parseContext.nestLooping();
3437
3438 // condition SEMI_COLON
3439 acceptExpression(condition);
3440 if (! acceptTokenClass(EHTokSemicolon))
3441 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003442 if (condition != nullptr) {
3443 condition = parseContext.convertConditionalExpression(loc, condition);
3444 if (condition == nullptr)
3445 return false;
3446 }
John Kessenich119f8f62016-06-05 15:44:07 -06003447
3448 // iterator SEMI_COLON
3449 TIntermTyped* iterator = nullptr;
3450 acceptExpression(iterator);
3451 if (! acceptTokenClass(EHTokRightParen))
3452 expected(")");
3453
3454 // statement
3455 if (! acceptScopedStatement(statement)) {
3456 expected("for sub-statement");
3457 return false;
3458 }
3459
steve-lunargf1709e72017-05-02 20:14:50 -06003460 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003461
3462 parseContext.popScope();
3463 parseContext.unnestLooping();
3464
3465 return true;
3466 }
3467
3468 default:
3469 return false;
3470 }
John Kessenich21472ae2016-06-04 11:46:33 -06003471}
3472
3473// jump_statement
3474// : CONTINUE SEMICOLON
3475// | BREAK SEMICOLON
3476// | DISCARD SEMICOLON
3477// | RETURN SEMICOLON
3478// | RETURN expression SEMICOLON
3479//
3480bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3481{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003482 EHlslTokenClass jump = peek();
3483 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003484 case EHTokContinue:
3485 case EHTokBreak:
3486 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003487 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003488 advanceToken();
3489 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003490 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003491 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003492 return false;
3493 }
John Kessenich21472ae2016-06-04 11:46:33 -06003494
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003495 switch (jump) {
3496 case EHTokContinue:
3497 statement = intermediate.addBranch(EOpContinue, token.loc);
3498 break;
3499 case EHTokBreak:
3500 statement = intermediate.addBranch(EOpBreak, token.loc);
3501 break;
3502 case EHTokDiscard:
3503 statement = intermediate.addBranch(EOpKill, token.loc);
3504 break;
3505
3506 case EHTokReturn:
3507 {
3508 // expression
3509 TIntermTyped* node;
3510 if (acceptExpression(node)) {
3511 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003512 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003513 } else
3514 statement = intermediate.addBranch(EOpReturn, token.loc);
3515 break;
3516 }
3517
3518 default:
3519 assert(0);
3520 return false;
3521 }
3522
3523 // SEMICOLON
3524 if (! acceptTokenClass(EHTokSemicolon))
3525 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003526
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003527 return true;
3528}
John Kessenich21472ae2016-06-04 11:46:33 -06003529
John Kessenichd02dc5d2016-07-01 00:04:11 -06003530// case_label
3531// : CASE expression COLON
3532//
John Kessenich21472ae2016-06-04 11:46:33 -06003533bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3534{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003535 TSourceLoc loc = token.loc;
3536 if (! acceptTokenClass(EHTokCase))
3537 return false;
3538
3539 TIntermTyped* expression;
3540 if (! acceptExpression(expression)) {
3541 expected("case expression");
3542 return false;
3543 }
3544
3545 if (! acceptTokenClass(EHTokColon)) {
3546 expected(":");
3547 return false;
3548 }
3549
3550 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3551
3552 return true;
3553}
3554
3555// default_label
3556// : DEFAULT COLON
3557//
3558bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3559{
3560 TSourceLoc loc = token.loc;
3561 if (! acceptTokenClass(EHTokDefault))
3562 return false;
3563
3564 if (! acceptTokenClass(EHTokColon)) {
3565 expected(":");
3566 return false;
3567 }
3568
3569 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3570
3571 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003572}
3573
John Kessenich19b92ff2016-06-19 11:50:34 -06003574// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003575// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3576// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003577//
3578void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3579{
3580 arraySizes = nullptr;
3581
steve-lunarg7b211a32016-10-13 12:26:18 -06003582 // Early-out if there aren't any array dimensions
3583 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003584 return;
3585
steve-lunarg7b211a32016-10-13 12:26:18 -06003586 // 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 -06003587 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003588
3589 // Collect each array dimension.
3590 while (acceptTokenClass(EHTokLeftBracket)) {
3591 TSourceLoc loc = token.loc;
3592 TIntermTyped* sizeExpr = nullptr;
3593
John Kessenich057df292017-03-06 18:18:37 -07003594 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003595 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3596
3597 if (! acceptTokenClass(EHTokRightBracket)) {
3598 expected("]");
3599 return;
3600 }
3601
3602 if (hasArraySize) {
3603 TArraySize arraySize;
3604 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3605 arraySizes->addInnerSize(arraySize);
3606 } else {
3607 arraySizes->addInnerSize(0); // sized by initializers.
3608 }
steve-lunarg265c0612016-09-27 10:57:35 -06003609 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003610}
3611
John Kessenich630dd7d2016-06-12 23:52:12 -06003612// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003613// : COLON semantic // optional
3614// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3615// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003616// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003617// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003618//
John Kessenich854fe242017-03-02 14:30:59 -07003619// Return true if any tokens were accepted. That is,
3620// false can be returned on successfully recognizing nothing,
3621// not necessarily meaning bad syntax.
3622//
3623bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003624{
John Kessenich854fe242017-03-02 14:30:59 -07003625 bool found = false;
3626
John Kessenich630dd7d2016-06-12 23:52:12 -06003627 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003628 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003629 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003630 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003631 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003632 if (peekTokenClass(EHTokLayout))
3633 acceptLayoutQualifierList(qualifier);
3634 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003635 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003636 if (! acceptTokenClass(EHTokLeftParen)) {
3637 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003638 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003639 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003640 HlslToken locationToken;
3641 if (! acceptIdentifier(locationToken)) {
3642 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003643 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003644 }
3645 HlslToken componentToken;
3646 if (acceptTokenClass(EHTokDot)) {
3647 if (! acceptIdentifier(componentToken)) {
3648 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003649 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003650 }
3651 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003652 if (! acceptTokenClass(EHTokRightParen)) {
3653 expected(")");
3654 break;
3655 }
John Kessenich7735b942016-09-05 12:40:06 -06003656 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003657 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003658 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003659 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003660 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003661 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3662 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003663 if (! acceptTokenClass(EHTokLeftParen)) {
3664 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003665 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003666 }
John Kessenichb38f0712016-07-30 10:29:54 -06003667 HlslToken registerDesc; // for Type#
3668 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003669 if (! acceptIdentifier(registerDesc)) {
3670 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003671 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003672 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003673 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3674 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003675 // Then we didn't really see the registerDesc yet, it was
3676 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003677 profile = registerDesc;
3678 if (! acceptIdentifier(registerDesc)) {
3679 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003680 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003681 }
3682 }
John Kessenichb38f0712016-07-30 10:29:54 -06003683 int subComponent = 0;
3684 if (acceptTokenClass(EHTokLeftBracket)) {
3685 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3686 if (! peekTokenClass(EHTokIntConstant)) {
3687 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003688 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003689 }
3690 subComponent = token.i;
3691 advanceToken();
3692 if (! acceptTokenClass(EHTokRightBracket)) {
3693 expected("]");
3694 break;
3695 }
3696 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003697 // (COMMA SPACEN)opt
3698 HlslToken spaceDesc;
3699 if (acceptTokenClass(EHTokComma)) {
3700 if (! acceptIdentifier(spaceDesc)) {
3701 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003702 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003703 }
3704 }
3705 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003706 if (! acceptTokenClass(EHTokRightParen)) {
3707 expected(")");
3708 break;
3709 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003710 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003711 } else {
3712 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003713 TString semanticUpperCase = *idToken.string;
3714 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3715 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003716 }
John Kessenich854fe242017-03-02 14:30:59 -07003717 } else if (peekTokenClass(EHTokLeftAngle)) {
3718 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003719 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003720 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003721 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003722
John Kessenich630dd7d2016-06-12 23:52:12 -06003723 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003724
3725 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003726}
3727
John Kessenichb16f7e62017-03-11 19:32:47 -07003728//
3729// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3730// processing.
3731//
3732bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3733{
3734 if (! peekTokenClass(EHTokLeftBrace))
3735 return false;
3736
3737 int braceCount = 0;
3738
3739 do {
3740 switch (peek()) {
3741 case EHTokLeftBrace:
3742 ++braceCount;
3743 break;
3744 case EHTokRightBrace:
3745 --braceCount;
3746 break;
3747 case EHTokNone:
3748 // End of input before balance { } is bad...
3749 return false;
3750 default:
3751 break;
3752 }
3753
3754 tokens.push_back(token);
3755 advanceToken();
3756 } while (braceCount > 0);
3757
3758 return true;
3759}
3760
John Kesseniche01a9bc2016-03-12 20:11:22 -07003761} // end namespace glslang