blob: 3b4bb4cd8ad8e6ac54aa2a9695f464202443a704 [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
311// | fully_specified_type declarator_list SEMICOLON
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);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600478 else if (variableType.getBasicType() == EbtBlock)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600479 parseContext.declareBlock(idToken.loc, variableType, fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600480 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700481 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600482 // this isn't really an individual variable, but a member of the $Global buffer
John Kessenich8f9fdc92017-03-30 16:22:26 -0600483 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600484 } else {
485 // Declare the variable and add any initializer code to the AST.
486 // The top-level node is always made into an aggregate, as that's
487 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700488 initializers = intermediate.growAggregate(initializers,
John Kessenich8f9fdc92017-03-30 16:22:26 -0600489 parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
John Kessenichca71d942017-03-07 20:44:09 -0700490 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600491 }
492 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600493 }
John Kessenich5f934b02016-03-13 17:58:25 -0600494 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600495
496 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700497 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600498 continue;
499 }
500 };
501
John Kessenichca71d942017-03-07 20:44:09 -0700502 // The top-level initializer node is a sequence.
503 if (initializers != nullptr)
504 initializers->setOperator(EOpSequence);
505
506 // Add the initializers' aggregate to the nodeList we were handed.
507 if (nodeList)
508 nodeList = intermediate.growAggregate(nodeList, initializers);
509 else
510 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700511
John Kessenich078d7f22016-03-14 10:02:11 -0600512 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600513 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700514 // This may have been a false detection of what appeared to be a declaration, but
515 // was actually an assignment such as "float = 4", where "float" is an identifier.
516 // We put the token back to let further parsing happen for cases where that may
517 // happen. This errors on the side of caution, and mostly triggers the error.
518
519 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
520 recedeToken();
521 else
522 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600523 return false;
524 }
John Kessenichecba76f2017-01-06 00:34:48 -0700525
John Kesseniche01a9bc2016-03-12 20:11:22 -0700526 return true;
527}
528
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600529// control_declaration
530// : fully_specified_type identifier EQUAL expression
531//
532bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
533{
534 node = nullptr;
535
536 // fully_specified_type
537 TType type;
538 if (! acceptFullySpecifiedType(type))
539 return false;
540
John Kessenich057df292017-03-06 18:18:37 -0700541 // filter out type casts
542 if (peekTokenClass(EHTokLeftParen)) {
543 recedeToken();
544 return false;
545 }
546
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600547 // identifier
548 HlslToken idToken;
549 if (! acceptIdentifier(idToken)) {
550 expected("identifier");
551 return false;
552 }
553
554 // EQUAL
555 TIntermTyped* expressionNode = nullptr;
556 if (! acceptTokenClass(EHTokAssign)) {
557 expected("=");
558 return false;
559 }
560
561 // expression
562 if (! acceptExpression(expressionNode)) {
563 expected("initializer");
564 return false;
565 }
566
John Kesseniche82061d2016-09-27 14:38:57 -0600567 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600568
569 return true;
570}
571
John Kessenich87142c72016-03-12 20:24:24 -0700572// fully_specified_type
573// : type_specifier
574// | type_qualifier type_specifier
575//
576bool HlslGrammar::acceptFullySpecifiedType(TType& type)
577{
John Kessenich54ee28f2017-03-11 14:13:00 -0700578 TIntermNode* nodeList = nullptr;
579 return acceptFullySpecifiedType(type, nodeList);
580}
581bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
582{
John Kessenich87142c72016-03-12 20:24:24 -0700583 // type_qualifier
584 TQualifier qualifier;
585 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600586 if (! acceptQualifier(qualifier))
587 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600588 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700589
590 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700591 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700592 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700593 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700594 // qualifier. Back it out, if we did.
595 if (qualifier.sample)
596 recedeToken();
597
John Kessenich87142c72016-03-12 20:24:24 -0700598 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700599 }
John Kessenich3d157c52016-07-25 16:05:33 -0600600 if (type.getBasicType() == EbtBlock) {
601 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600602 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600603 // further, it can create an anonymous instance of the block
604 if (peekTokenClass(EHTokSemicolon))
605 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600606 } else {
607 // Some qualifiers are set when parsing the type. Merge those with
608 // whatever comes from acceptQualifier.
609 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700610
steve-lunargbb0183f2016-10-04 16:58:14 -0600611 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600612 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700613
steve-lunarg08e0c082017-03-29 20:01:13 -0600614 if (type.getQualifier().storage == EvqOut ||
steve-lunarg5da1f032017-02-12 17:50:28 -0700615 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700616 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700617 qualifier.readonly = type.getQualifier().readonly;
618 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700619
steve-lunarg08e0c082017-03-29 20:01:13 -0600620 if (type.getQualifier().builtIn != EbvNone)
621 qualifier.builtIn = type.getQualifier().builtIn;
622
steve-lunargf49cdf42016-11-17 15:04:20 -0700623 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600624 }
John Kessenich87142c72016-03-12 20:24:24 -0700625
626 return true;
627}
628
John Kessenich630dd7d2016-06-12 23:52:12 -0600629// type_qualifier
630// : qualifier qualifier ...
631//
632// Zero or more of these, so this can't return false.
633//
John Kessenichb9e39122016-08-17 10:22:08 -0600634bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700635{
John Kessenich630dd7d2016-06-12 23:52:12 -0600636 do {
637 switch (peek()) {
638 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600639 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600640 break;
641 case EHTokExtern:
642 // TODO: no meaning in glslang?
643 break;
644 case EHTokShared:
645 // TODO: hint
646 break;
647 case EHTokGroupShared:
648 qualifier.storage = EvqShared;
649 break;
650 case EHTokUniform:
651 qualifier.storage = EvqUniform;
652 break;
653 case EHTokConst:
654 qualifier.storage = EvqConst;
655 break;
656 case EHTokVolatile:
657 qualifier.volatil = true;
658 break;
659 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600660 qualifier.smooth = true;
661 break;
662 case EHTokCentroid:
663 qualifier.centroid = true;
664 break;
665 case EHTokNointerpolation:
666 qualifier.flat = true;
667 break;
668 case EHTokNoperspective:
669 qualifier.nopersp = true;
670 break;
671 case EHTokSample:
672 qualifier.sample = true;
673 break;
674 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600675 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600676 break;
677 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600678 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600679 break;
680 case EHTokPrecise:
681 qualifier.noContraction = true;
682 break;
LoopDawg9249c702016-07-12 20:44:32 -0600683 case EHTokIn:
684 qualifier.storage = EvqIn;
685 break;
686 case EHTokOut:
687 qualifier.storage = EvqOut;
688 break;
689 case EHTokInOut:
690 qualifier.storage = EvqInOut;
691 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600692 case EHTokLayout:
693 if (! acceptLayoutQualifierList(qualifier))
694 return false;
695 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700696 case EHTokGloballyCoherent:
697 qualifier.coherent = true;
698 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600699 case EHTokInline:
700 // TODO: map this to SPIR-V function control
701 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700702
703 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
704 // for output variables.
705 case EHTokPoint:
706 qualifier.storage = EvqIn;
707 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
708 return false;
709 break;
710 case EHTokLine:
711 qualifier.storage = EvqIn;
712 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
713 return false;
714 break;
715 case EHTokTriangle:
716 qualifier.storage = EvqIn;
717 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
718 return false;
719 break;
720 case EHTokLineAdj:
721 qualifier.storage = EvqIn;
722 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
723 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700724 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700725 case EHTokTriangleAdj:
726 qualifier.storage = EvqIn;
727 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
728 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700729 break;
730
John Kessenich630dd7d2016-06-12 23:52:12 -0600731 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600732 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600733 }
734 advanceToken();
735 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700736}
737
John Kessenichb9e39122016-08-17 10:22:08 -0600738// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600739// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600740//
741// layout_qualifier
742// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600743// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600744//
745// Zero or more of these, so this can't return false.
746//
747bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
748{
749 if (! acceptTokenClass(EHTokLayout))
750 return false;
751
752 // LEFT_PAREN
753 if (! acceptTokenClass(EHTokLeftParen))
754 return false;
755
756 do {
757 // identifier
758 HlslToken idToken;
759 if (! acceptIdentifier(idToken))
760 break;
761
762 // EQUAL expression
763 if (acceptTokenClass(EHTokAssign)) {
764 TIntermTyped* expr;
765 if (! acceptConditionalExpression(expr)) {
766 expected("expression");
767 return false;
768 }
769 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
770 } else
771 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
772
773 // COMMA
774 if (! acceptTokenClass(EHTokComma))
775 break;
776 } while (true);
777
778 // RIGHT_PAREN
779 if (! acceptTokenClass(EHTokRightParen)) {
780 expected(")");
781 return false;
782 }
783
784 return true;
785}
786
LoopDawg6daaa4f2016-06-23 19:13:48 -0600787// template_type
788// : FLOAT
789// | DOUBLE
790// | INT
791// | DWORD
792// | UINT
793// | BOOL
794//
steve-lunargf49cdf42016-11-17 15:04:20 -0700795bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600796{
797 switch (peek()) {
798 case EHTokFloat:
799 basicType = EbtFloat;
800 break;
801 case EHTokDouble:
802 basicType = EbtDouble;
803 break;
804 case EHTokInt:
805 case EHTokDword:
806 basicType = EbtInt;
807 break;
808 case EHTokUint:
809 basicType = EbtUint;
810 break;
811 case EHTokBool:
812 basicType = EbtBool;
813 break;
814 default:
815 return false;
816 }
817
818 advanceToken();
819
820 return true;
821}
822
823// vector_template_type
824// : VECTOR
825// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
826//
827bool HlslGrammar::acceptVectorTemplateType(TType& type)
828{
829 if (! acceptTokenClass(EHTokVector))
830 return false;
831
832 if (! acceptTokenClass(EHTokLeftAngle)) {
833 // in HLSL, 'vector' alone means float4.
834 new(&type) TType(EbtFloat, EvqTemporary, 4);
835 return true;
836 }
837
838 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700839 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600840 expected("scalar type");
841 return false;
842 }
843
844 // COMMA
845 if (! acceptTokenClass(EHTokComma)) {
846 expected(",");
847 return false;
848 }
849
850 // integer
851 if (! peekTokenClass(EHTokIntConstant)) {
852 expected("literal integer");
853 return false;
854 }
855
856 TIntermTyped* vecSize;
857 if (! acceptLiteral(vecSize))
858 return false;
859
860 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
861
862 new(&type) TType(basicType, EvqTemporary, vecSizeI);
863
864 if (vecSizeI == 1)
865 type.makeVector();
866
867 if (!acceptTokenClass(EHTokRightAngle)) {
868 expected("right angle bracket");
869 return false;
870 }
871
872 return true;
873}
874
875// matrix_template_type
876// : MATRIX
877// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
878//
879bool HlslGrammar::acceptMatrixTemplateType(TType& type)
880{
881 if (! acceptTokenClass(EHTokMatrix))
882 return false;
883
884 if (! acceptTokenClass(EHTokLeftAngle)) {
885 // in HLSL, 'matrix' alone means float4x4.
886 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
887 return true;
888 }
889
890 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700891 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600892 expected("scalar type");
893 return false;
894 }
895
896 // COMMA
897 if (! acceptTokenClass(EHTokComma)) {
898 expected(",");
899 return false;
900 }
901
902 // integer rows
903 if (! peekTokenClass(EHTokIntConstant)) {
904 expected("literal integer");
905 return false;
906 }
907
908 TIntermTyped* rows;
909 if (! acceptLiteral(rows))
910 return false;
911
912 // COMMA
913 if (! acceptTokenClass(EHTokComma)) {
914 expected(",");
915 return false;
916 }
John Kessenichecba76f2017-01-06 00:34:48 -0700917
LoopDawg6daaa4f2016-06-23 19:13:48 -0600918 // integer cols
919 if (! peekTokenClass(EHTokIntConstant)) {
920 expected("literal integer");
921 return false;
922 }
923
924 TIntermTyped* cols;
925 if (! acceptLiteral(cols))
926 return false;
927
928 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600929 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
930 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600931
932 if (!acceptTokenClass(EHTokRightAngle)) {
933 expected("right angle bracket");
934 return false;
935 }
936
937 return true;
938}
939
steve-lunargf49cdf42016-11-17 15:04:20 -0700940// layout_geometry
941// : LINESTREAM
942// | POINTSTREAM
943// | TRIANGLESTREAM
944//
945bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
946{
947 // read geometry type
948 const EHlslTokenClass geometryType = peek();
949
950 switch (geometryType) {
951 case EHTokPointStream: geometry = ElgPoints; break;
952 case EHTokLineStream: geometry = ElgLineStrip; break;
953 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
954 default:
955 return false; // not a layout geometry
956 }
957
958 advanceToken(); // consume the layout keyword
959 return true;
960}
961
steve-lunarg858c9282017-01-07 08:54:10 -0700962// tessellation_decl_type
963// : INPUTPATCH
964// | OUTPUTPATCH
965//
steve-lunarg067eb9b2017-04-01 15:34:48 -0600966bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
steve-lunarg858c9282017-01-07 08:54:10 -0700967{
968 // read geometry type
969 const EHlslTokenClass tessType = peek();
970
971 switch (tessType) {
steve-lunarg067eb9b2017-04-01 15:34:48 -0600972 case EHTokInputPatch: patchType = EbvInputPatch; break;
973 case EHTokOutputPatch: patchType = EbvOutputPatch; break;
steve-lunarg858c9282017-01-07 08:54:10 -0700974 default:
975 return false; // not a tessellation decl
976 }
977
978 advanceToken(); // consume the keyword
979 return true;
980}
981
982// tessellation_patch_template_type
983// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
984//
985bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
986{
steve-lunarg067eb9b2017-04-01 15:34:48 -0600987 TBuiltInVariable patchType;
988
989 if (! acceptTessellationDeclType(patchType))
steve-lunarg858c9282017-01-07 08:54:10 -0700990 return false;
991
992 if (! acceptTokenClass(EHTokLeftAngle))
993 return false;
994
995 if (! acceptType(type)) {
996 expected("tessellation patch type");
997 return false;
998 }
999
1000 if (! acceptTokenClass(EHTokComma))
1001 return false;
1002
1003 // integer size
1004 if (! peekTokenClass(EHTokIntConstant)) {
1005 expected("literal integer");
1006 return false;
1007 }
1008
1009 TIntermTyped* size;
1010 if (! acceptLiteral(size))
1011 return false;
1012
1013 TArraySizes* arraySizes = new TArraySizes;
1014 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1015 type.newArraySizes(*arraySizes);
steve-lunarg067eb9b2017-04-01 15:34:48 -06001016 type.getQualifier().builtIn = patchType;
steve-lunarg858c9282017-01-07 08:54:10 -07001017
1018 if (! acceptTokenClass(EHTokRightAngle)) {
1019 expected("right angle bracket");
1020 return false;
1021 }
1022
1023 return true;
1024}
1025
steve-lunargf49cdf42016-11-17 15:04:20 -07001026// stream_out_template_type
1027// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1028//
1029bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1030{
1031 geometry = ElgNone;
1032
1033 if (! acceptOutputPrimitiveGeometry(geometry))
1034 return false;
1035
1036 if (! acceptTokenClass(EHTokLeftAngle))
1037 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001038
steve-lunargf49cdf42016-11-17 15:04:20 -07001039 if (! acceptType(type)) {
1040 expected("stream output type");
1041 return false;
1042 }
1043
steve-lunarg08e0c082017-03-29 20:01:13 -06001044 type.getQualifier().storage = EvqOut;
1045 type.getQualifier().builtIn = EbvGsOutputStream;
steve-lunargf49cdf42016-11-17 15:04:20 -07001046
1047 if (! acceptTokenClass(EHTokRightAngle)) {
1048 expected("right angle bracket");
1049 return false;
1050 }
1051
1052 return true;
1053}
John Kessenichecba76f2017-01-06 00:34:48 -07001054
John Kessenicha1e2d492016-09-20 13:22:58 -06001055// annotations
1056// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001057//
John Kessenicha1e2d492016-09-20 13:22:58 -06001058bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001059{
John Kessenicha1e2d492016-09-20 13:22:58 -06001060 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001061 return false;
1062
John Kessenicha1e2d492016-09-20 13:22:58 -06001063 // note that we are nesting a name space
1064 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001065
1066 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1067 do {
1068 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1069 while (acceptTokenClass(EHTokSemicolon))
1070 ;
1071
1072 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001073 break;
John Kessenich86f71382016-09-19 20:23:18 -06001074
1075 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001076 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001077 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001078 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001079 return false;
1080 }
1081 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001082
1083 parseContext.unnestAnnotations();
1084 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001085}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001086
LoopDawg4886f692016-06-29 10:58:58 -06001087// sampler_type
1088// : SAMPLER
1089// | SAMPLER1D
1090// | SAMPLER2D
1091// | SAMPLER3D
1092// | SAMPLERCUBE
1093// | SAMPLERSTATE
1094// | SAMPLERCOMPARISONSTATE
1095bool HlslGrammar::acceptSamplerType(TType& type)
1096{
1097 // read sampler type
1098 const EHlslTokenClass samplerType = peek();
1099
LoopDawga78b0292016-07-19 14:28:05 -06001100 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001101 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001102
LoopDawga78b0292016-07-19 14:28:05 -06001103 bool isShadow = false;
1104
LoopDawg4886f692016-06-29 10:58:58 -06001105 switch (samplerType) {
1106 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001107 case EHTokSampler1d: /*dim = Esd1D*/; break;
1108 case EHTokSampler2d: /*dim = Esd2D*/; break;
1109 case EHTokSampler3d: /*dim = Esd3D*/; break;
1110 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001111 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001112 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001113 default:
1114 return false; // not a sampler declaration
1115 }
1116
1117 advanceToken(); // consume the sampler type keyword
1118
1119 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001120
1121 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001122 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001123
1124 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1125
1126 return true;
1127}
1128
1129// texture_type
1130// | BUFFER
1131// | TEXTURE1D
1132// | TEXTURE1DARRAY
1133// | TEXTURE2D
1134// | TEXTURE2DARRAY
1135// | TEXTURE3D
1136// | TEXTURECUBE
1137// | TEXTURECUBEARRAY
1138// | TEXTURE2DMS
1139// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001140// | RWBUFFER
1141// | RWTEXTURE1D
1142// | RWTEXTURE1DARRAY
1143// | RWTEXTURE2D
1144// | RWTEXTURE2DARRAY
1145// | RWTEXTURE3D
1146
LoopDawg4886f692016-06-29 10:58:58 -06001147bool HlslGrammar::acceptTextureType(TType& type)
1148{
1149 const EHlslTokenClass textureType = peek();
1150
1151 TSamplerDim dim = EsdNone;
1152 bool array = false;
1153 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001154 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001155 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001156
1157 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001158 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001159 case EHTokTexture1d: dim = Esd1D; break;
1160 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1161 case EHTokTexture2d: dim = Esd2D; break;
1162 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1163 case EHTokTexture3d: dim = Esd3D; break;
1164 case EHTokTextureCube: dim = EsdCube; break;
1165 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1166 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1167 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1168 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1169 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1170 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1171 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1172 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1173 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001174 default:
1175 return false; // not a texture declaration
1176 }
1177
1178 advanceToken(); // consume the texture object keyword
1179
1180 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001181
LoopDawg4886f692016-06-29 10:58:58 -06001182 TIntermTyped* msCount = nullptr;
1183
steve-lunargbb0183f2016-10-04 16:58:14 -06001184 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001185 if (acceptTokenClass(EHTokLeftAngle)) {
1186 if (! acceptType(txType)) {
1187 expected("scalar or vector type");
1188 return false;
1189 }
1190
1191 const TBasicType basicRetType = txType.getBasicType() ;
1192
1193 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1194 unimplemented("basic type in texture");
1195 return false;
1196 }
1197
steve-lunargd53f7172016-07-27 15:46:48 -06001198 // Buffers can handle small mats if they fit in 4 components
1199 if (dim == EsdBuffer && txType.isMatrix()) {
1200 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1201 expected("components < 4 in matrix buffer type");
1202 return false;
1203 }
1204
1205 // TODO: except we don't handle it yet...
1206 unimplemented("matrix type in buffer");
1207 return false;
1208 }
1209
LoopDawg4886f692016-06-29 10:58:58 -06001210 if (!txType.isScalar() && !txType.isVector()) {
1211 expected("scalar or vector type");
1212 return false;
1213 }
1214
LoopDawg4886f692016-06-29 10:58:58 -06001215 if (ms && acceptTokenClass(EHTokComma)) {
1216 // read sample count for multisample types, if given
1217 if (! peekTokenClass(EHTokIntConstant)) {
1218 expected("multisample count");
1219 return false;
1220 }
1221
1222 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1223 return false;
1224 }
1225
1226 if (! acceptTokenClass(EHTokRightAngle)) {
1227 expected("right angle bracket");
1228 return false;
1229 }
1230 } else if (ms) {
1231 expected("texture type for multisample");
1232 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001233 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001234 expected("type for RWTexture/RWBuffer");
1235 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001236 }
1237
1238 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001239 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001240
1241 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001242 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001243
steve-lunarg4f2da272016-10-10 15:24:57 -06001244 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1245 if (image || dim == EsdBuffer)
1246 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001247
1248 // Non-image Buffers are combined
1249 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001250 sampler.set(txType.getBasicType(), dim, array);
1251 } else {
1252 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001253 if (image) {
1254 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1255 } else {
1256 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1257 }
steve-lunargd53f7172016-07-27 15:46:48 -06001258 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001259
1260 // Remember the declared vector size.
1261 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001262
steve-lunargbf1537f2017-03-31 17:40:09 -06001263 // Force uncombined, if necessary
1264 if (!combined)
1265 sampler.combined = false;
1266
LoopDawg4886f692016-06-29 10:58:58 -06001267 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001268 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001269
1270 return true;
1271}
1272
John Kessenich87142c72016-03-12 20:24:24 -07001273// If token is for a type, update 'type' with the type information,
1274// and return true and advance.
1275// Otherwise, return false, and don't advance
1276bool HlslGrammar::acceptType(TType& type)
1277{
John Kessenich54ee28f2017-03-11 14:13:00 -07001278 TIntermNode* nodeList = nullptr;
1279 return acceptType(type, nodeList);
1280}
1281bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1282{
steve-lunarg3226b082016-10-26 19:18:55 -06001283 // Basic types for min* types, broken out here in case of future
1284 // changes, e.g, to use native halfs.
1285 static const TBasicType min16float_bt = EbtFloat;
1286 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001287 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001288 static const TBasicType min16int_bt = EbtInt;
1289 static const TBasicType min12int_bt = EbtInt;
1290 static const TBasicType min16uint_bt = EbtUint;
1291
John Kessenich9c86c6a2016-05-03 22:49:24 -06001292 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001293 case EHTokVector:
1294 return acceptVectorTemplateType(type);
1295 break;
1296
1297 case EHTokMatrix:
1298 return acceptMatrixTemplateType(type);
1299 break;
1300
steve-lunargf49cdf42016-11-17 15:04:20 -07001301 case EHTokPointStream: // fall through
1302 case EHTokLineStream: // ...
1303 case EHTokTriangleStream: // ...
1304 {
1305 TLayoutGeometry geometry;
1306 if (! acceptStreamOutTemplateType(type, geometry))
1307 return false;
1308
1309 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1310 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001311
steve-lunargf49cdf42016-11-17 15:04:20 -07001312 return true;
1313 }
1314
steve-lunarg858c9282017-01-07 08:54:10 -07001315 case EHTokInputPatch: // fall through
1316 case EHTokOutputPatch: // ...
1317 {
1318 if (! acceptTessellationPatchTemplateType(type))
1319 return false;
1320
1321 return true;
1322 }
1323
LoopDawg4886f692016-06-29 10:58:58 -06001324 case EHTokSampler: // fall through
1325 case EHTokSampler1d: // ...
1326 case EHTokSampler2d: // ...
1327 case EHTokSampler3d: // ...
1328 case EHTokSamplerCube: // ...
1329 case EHTokSamplerState: // ...
1330 case EHTokSamplerComparisonState: // ...
1331 return acceptSamplerType(type);
1332 break;
1333
1334 case EHTokBuffer: // fall through
1335 case EHTokTexture1d: // ...
1336 case EHTokTexture1darray: // ...
1337 case EHTokTexture2d: // ...
1338 case EHTokTexture2darray: // ...
1339 case EHTokTexture3d: // ...
1340 case EHTokTextureCube: // ...
1341 case EHTokTextureCubearray: // ...
1342 case EHTokTexture2DMS: // ...
1343 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001344 case EHTokRWTexture1d: // ...
1345 case EHTokRWTexture1darray: // ...
1346 case EHTokRWTexture2d: // ...
1347 case EHTokRWTexture2darray: // ...
1348 case EHTokRWTexture3d: // ...
1349 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001350 return acceptTextureType(type);
1351 break;
1352
steve-lunarg5da1f032017-02-12 17:50:28 -07001353 case EHTokAppendStructuredBuffer:
1354 case EHTokByteAddressBuffer:
1355 case EHTokConsumeStructuredBuffer:
1356 case EHTokRWByteAddressBuffer:
1357 case EHTokRWStructuredBuffer:
1358 case EHTokStructuredBuffer:
1359 return acceptStructBufferType(type);
1360 break;
1361
John Kessenich27ffb292017-03-03 17:01:01 -07001362 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001363 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001364 case EHTokCBuffer:
1365 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001366 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001367
1368 case EHTokIdentifier:
1369 // An identifier could be for a user-defined type.
1370 // Note we cache the symbol table lookup, to save for a later rule
1371 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001372 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001373 advanceToken();
1374 return true;
1375 } else
1376 return false;
1377
John Kessenich71351de2016-06-08 12:50:56 -06001378 case EHTokVoid:
1379 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001380 break;
John Kessenich71351de2016-06-08 12:50:56 -06001381
John Kessenicha1e2d492016-09-20 13:22:58 -06001382 case EHTokString:
1383 new(&type) TType(EbtString);
1384 break;
1385
John Kessenich87142c72016-03-12 20:24:24 -07001386 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001387 new(&type) TType(EbtFloat);
1388 break;
John Kessenich87142c72016-03-12 20:24:24 -07001389 case EHTokFloat1:
1390 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001391 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001392 break;
John Kessenich87142c72016-03-12 20:24:24 -07001393 case EHTokFloat2:
1394 new(&type) TType(EbtFloat, EvqTemporary, 2);
1395 break;
1396 case EHTokFloat3:
1397 new(&type) TType(EbtFloat, EvqTemporary, 3);
1398 break;
1399 case EHTokFloat4:
1400 new(&type) TType(EbtFloat, EvqTemporary, 4);
1401 break;
1402
John Kessenich71351de2016-06-08 12:50:56 -06001403 case EHTokDouble:
1404 new(&type) TType(EbtDouble);
1405 break;
1406 case EHTokDouble1:
1407 new(&type) TType(EbtDouble);
1408 type.makeVector();
1409 break;
1410 case EHTokDouble2:
1411 new(&type) TType(EbtDouble, EvqTemporary, 2);
1412 break;
1413 case EHTokDouble3:
1414 new(&type) TType(EbtDouble, EvqTemporary, 3);
1415 break;
1416 case EHTokDouble4:
1417 new(&type) TType(EbtDouble, EvqTemporary, 4);
1418 break;
1419
1420 case EHTokInt:
1421 case EHTokDword:
1422 new(&type) TType(EbtInt);
1423 break;
1424 case EHTokInt1:
1425 new(&type) TType(EbtInt);
1426 type.makeVector();
1427 break;
John Kessenich87142c72016-03-12 20:24:24 -07001428 case EHTokInt2:
1429 new(&type) TType(EbtInt, EvqTemporary, 2);
1430 break;
1431 case EHTokInt3:
1432 new(&type) TType(EbtInt, EvqTemporary, 3);
1433 break;
1434 case EHTokInt4:
1435 new(&type) TType(EbtInt, EvqTemporary, 4);
1436 break;
1437
John Kessenich71351de2016-06-08 12:50:56 -06001438 case EHTokUint:
1439 new(&type) TType(EbtUint);
1440 break;
1441 case EHTokUint1:
1442 new(&type) TType(EbtUint);
1443 type.makeVector();
1444 break;
1445 case EHTokUint2:
1446 new(&type) TType(EbtUint, EvqTemporary, 2);
1447 break;
1448 case EHTokUint3:
1449 new(&type) TType(EbtUint, EvqTemporary, 3);
1450 break;
1451 case EHTokUint4:
1452 new(&type) TType(EbtUint, EvqTemporary, 4);
1453 break;
1454
1455 case EHTokBool:
1456 new(&type) TType(EbtBool);
1457 break;
1458 case EHTokBool1:
1459 new(&type) TType(EbtBool);
1460 type.makeVector();
1461 break;
John Kessenich87142c72016-03-12 20:24:24 -07001462 case EHTokBool2:
1463 new(&type) TType(EbtBool, EvqTemporary, 2);
1464 break;
1465 case EHTokBool3:
1466 new(&type) TType(EbtBool, EvqTemporary, 3);
1467 break;
1468 case EHTokBool4:
1469 new(&type) TType(EbtBool, EvqTemporary, 4);
1470 break;
1471
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001472 case EHTokHalf:
1473 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1474 break;
1475 case EHTokHalf1:
1476 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1477 type.makeVector();
1478 break;
1479 case EHTokHalf2:
1480 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1481 break;
1482 case EHTokHalf3:
1483 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1484 break;
1485 case EHTokHalf4:
1486 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1487 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001488
steve-lunarg3226b082016-10-26 19:18:55 -06001489 case EHTokMin16float:
1490 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1491 break;
1492 case EHTokMin16float1:
1493 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1494 type.makeVector();
1495 break;
1496 case EHTokMin16float2:
1497 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1498 break;
1499 case EHTokMin16float3:
1500 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1501 break;
1502 case EHTokMin16float4:
1503 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1504 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001505
steve-lunarg3226b082016-10-26 19:18:55 -06001506 case EHTokMin10float:
1507 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1508 break;
1509 case EHTokMin10float1:
1510 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1511 type.makeVector();
1512 break;
1513 case EHTokMin10float2:
1514 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1515 break;
1516 case EHTokMin10float3:
1517 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1518 break;
1519 case EHTokMin10float4:
1520 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1521 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001522
steve-lunarg3226b082016-10-26 19:18:55 -06001523 case EHTokMin16int:
1524 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1525 break;
1526 case EHTokMin16int1:
1527 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1528 type.makeVector();
1529 break;
1530 case EHTokMin16int2:
1531 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1532 break;
1533 case EHTokMin16int3:
1534 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1535 break;
1536 case EHTokMin16int4:
1537 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1538 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001539
steve-lunarg3226b082016-10-26 19:18:55 -06001540 case EHTokMin12int:
1541 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1542 break;
1543 case EHTokMin12int1:
1544 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1545 type.makeVector();
1546 break;
1547 case EHTokMin12int2:
1548 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1549 break;
1550 case EHTokMin12int3:
1551 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1552 break;
1553 case EHTokMin12int4:
1554 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1555 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001556
steve-lunarg3226b082016-10-26 19:18:55 -06001557 case EHTokMin16uint:
1558 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1559 break;
1560 case EHTokMin16uint1:
1561 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1562 type.makeVector();
1563 break;
1564 case EHTokMin16uint2:
1565 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1566 break;
1567 case EHTokMin16uint3:
1568 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1569 break;
1570 case EHTokMin16uint4:
1571 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1572 break;
1573
John Kessenich0133c122016-05-20 12:17:26 -06001574 case EHTokInt1x1:
1575 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1576 break;
1577 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001578 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001579 break;
1580 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001581 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001582 break;
1583 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001584 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001585 break;
1586 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001587 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001588 break;
1589 case EHTokInt2x2:
1590 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1591 break;
1592 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001593 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001594 break;
1595 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001596 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001597 break;
1598 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001599 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001600 break;
1601 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001603 break;
1604 case EHTokInt3x3:
1605 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1606 break;
1607 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001608 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001609 break;
1610 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001611 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001612 break;
1613 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001614 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001615 break;
1616 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001618 break;
1619 case EHTokInt4x4:
1620 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1621 break;
1622
John Kessenich71351de2016-06-08 12:50:56 -06001623 case EHTokUint1x1:
1624 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1625 break;
1626 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001627 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001628 break;
1629 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001630 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001631 break;
1632 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001633 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001634 break;
1635 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001636 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001637 break;
1638 case EHTokUint2x2:
1639 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1640 break;
1641 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001642 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001643 break;
1644 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001645 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001646 break;
1647 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001648 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001649 break;
1650 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001651 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001652 break;
1653 case EHTokUint3x3:
1654 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1655 break;
1656 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001657 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001658 break;
1659 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001660 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001661 break;
1662 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001663 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001664 break;
1665 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001666 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001667 break;
1668 case EHTokUint4x4:
1669 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1670 break;
1671
1672 case EHTokBool1x1:
1673 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1674 break;
1675 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001676 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001677 break;
1678 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001679 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001680 break;
1681 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001682 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001683 break;
1684 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001685 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001686 break;
1687 case EHTokBool2x2:
1688 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1689 break;
1690 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001691 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001692 break;
1693 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001694 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001695 break;
1696 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001697 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001698 break;
1699 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001700 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001701 break;
1702 case EHTokBool3x3:
1703 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1704 break;
1705 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001706 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001707 break;
1708 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001709 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001710 break;
1711 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001712 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001713 break;
1714 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001715 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001716 break;
1717 case EHTokBool4x4:
1718 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1719 break;
1720
John Kessenich0133c122016-05-20 12:17:26 -06001721 case EHTokFloat1x1:
1722 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1723 break;
1724 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001725 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001726 break;
1727 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001728 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001729 break;
1730 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001731 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001732 break;
1733 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001734 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001735 break;
John Kessenich87142c72016-03-12 20:24:24 -07001736 case EHTokFloat2x2:
1737 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1738 break;
1739 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001740 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001741 break;
1742 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001743 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001744 break;
John Kessenich0133c122016-05-20 12:17:26 -06001745 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001746 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001747 break;
John Kessenich87142c72016-03-12 20:24:24 -07001748 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001749 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001750 break;
1751 case EHTokFloat3x3:
1752 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1753 break;
1754 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001755 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001756 break;
John Kessenich0133c122016-05-20 12:17:26 -06001757 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001758 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001759 break;
John Kessenich87142c72016-03-12 20:24:24 -07001760 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001761 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001762 break;
1763 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001764 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001765 break;
1766 case EHTokFloat4x4:
1767 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1768 break;
1769
John Kessenich0133c122016-05-20 12:17:26 -06001770 case EHTokDouble1x1:
1771 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1772 break;
1773 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001774 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001775 break;
1776 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001777 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001778 break;
1779 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001780 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001781 break;
1782 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001783 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001784 break;
1785 case EHTokDouble2x2:
1786 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1787 break;
1788 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001789 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001790 break;
1791 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001792 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001793 break;
1794 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001795 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001796 break;
1797 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001798 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001799 break;
1800 case EHTokDouble3x3:
1801 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1802 break;
1803 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001804 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001805 break;
1806 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001807 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001808 break;
1809 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001810 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001811 break;
1812 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001813 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001814 break;
1815 case EHTokDouble4x4:
1816 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1817 break;
1818
John Kessenich87142c72016-03-12 20:24:24 -07001819 default:
1820 return false;
1821 }
1822
1823 advanceToken();
1824
1825 return true;
1826}
1827
John Kesseniche6e74942016-06-11 16:43:14 -06001828// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001829// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1830// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001831// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001832//
1833// struct_type
1834// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001835// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001836// | CBUFFER
1837// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001838//
John Kessenich54ee28f2017-03-11 14:13:00 -07001839bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001840{
John Kessenichb804de62016-09-05 12:19:18 -06001841 // This storage qualifier will tell us whether it's an AST
1842 // block type or just a generic structure type.
1843 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001844
1845 // CBUFFER
1846 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001847 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001848 // TBUFFER
1849 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001850 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001851 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001852 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001853 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001854 return false;
1855
1856 // IDENTIFIER
1857 TString structName = "";
1858 if (peekTokenClass(EHTokIdentifier)) {
1859 structName = *token.string;
1860 advanceToken();
1861 }
1862
John Kessenich3d157c52016-07-25 16:05:33 -06001863 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001864 TQualifier postDeclQualifier;
1865 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001866 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001867
John Kessenichf3d88bd2017-03-19 12:24:29 -06001868 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001869 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001870 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001871 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1872 // struct_type IDENTIFIER
1873 return true;
1874 } else {
1875 expected("{");
1876 return false;
1877 }
John Kesseniche6e74942016-06-11 16:43:14 -06001878 }
1879
John Kessenichf3d88bd2017-03-19 12:24:29 -06001880
John Kesseniche6e74942016-06-11 16:43:14 -06001881 // struct_declaration_list
1882 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001883 // Save each member function so they can be processed after we have a fully formed 'this'.
1884 TVector<TFunctionDeclarator> functionDeclarators;
1885
1886 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001887 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001888 parseContext.popNamespace();
1889
1890 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001891 expected("struct member declarations");
1892 return false;
1893 }
1894
1895 // RIGHT_BRACE
1896 if (! acceptTokenClass(EHTokRightBrace)) {
1897 expected("}");
1898 return false;
1899 }
1900
1901 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001902 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001903 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001904 else {
John Kessenich7735b942016-09-05 12:40:06 -06001905 postDeclQualifier.storage = storageQualifier;
1906 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001907 }
John Kesseniche6e74942016-06-11 16:43:14 -06001908
John Kessenich727b3742017-02-03 17:57:55 -07001909 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001910
John Kessenich4960baa2017-03-19 18:09:59 -06001911 // For member functions: now that we know the type of 'this', go back and
1912 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1913 // - parse the functions, their tokens were saved for deferred parsing (now)
1914 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1915 // update signature
1916 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001917 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001918 }
1919
John Kessenichf3d88bd2017-03-19 12:24:29 -06001920 // All member functions get parsed inside the class/struct namespace and with the
1921 // class/struct members in a symbol-table level.
1922 parseContext.pushNamespace(structName);
John Kessenich37789792017-03-21 23:56:40 -06001923 parseContext.pushThisScope(type);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001924 bool deferredSuccess = true;
1925 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1926 // parse body
1927 pushTokenStream(functionDeclarators[b].body);
1928 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1929 deferredSuccess = false;
1930 popTokenStream();
1931 }
John Kessenich37789792017-03-21 23:56:40 -06001932 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001933 parseContext.popNamespace();
1934
1935 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001936}
1937
steve-lunarg5da1f032017-02-12 17:50:28 -07001938// struct_buffer
1939// : APPENDSTRUCTUREDBUFFER
1940// | BYTEADDRESSBUFFER
1941// | CONSUMESTRUCTUREDBUFFER
1942// | RWBYTEADDRESSBUFFER
1943// | RWSTRUCTUREDBUFFER
1944// | STRUCTUREDBUFFER
1945bool HlslGrammar::acceptStructBufferType(TType& type)
1946{
1947 const EHlslTokenClass structBuffType = peek();
1948
1949 // TODO: globallycoherent
1950 bool hasTemplateType = true;
1951 bool readonly = false;
1952
1953 TStorageQualifier storage = EvqBuffer;
1954
1955 switch (structBuffType) {
1956 case EHTokAppendStructuredBuffer:
1957 unimplemented("AppendStructuredBuffer");
1958 return false;
1959 case EHTokByteAddressBuffer:
1960 hasTemplateType = false;
1961 readonly = true;
1962 break;
1963 case EHTokConsumeStructuredBuffer:
1964 unimplemented("ConsumeStructuredBuffer");
1965 return false;
1966 case EHTokRWByteAddressBuffer:
1967 hasTemplateType = false;
1968 break;
1969 case EHTokRWStructuredBuffer:
1970 break;
1971 case EHTokStructuredBuffer:
1972 readonly = true;
1973 break;
1974 default:
1975 return false; // not a structure buffer type
1976 }
1977
1978 advanceToken(); // consume the structure keyword
1979
1980 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1981 TType* templateType = new TType;
1982
1983 if (hasTemplateType) {
1984 if (! acceptTokenClass(EHTokLeftAngle)) {
1985 expected("left angle bracket");
1986 return false;
1987 }
1988
1989 if (! acceptType(*templateType)) {
1990 expected("type");
1991 return false;
1992 }
1993 if (! acceptTokenClass(EHTokRightAngle)) {
1994 expected("right angle bracket");
1995 return false;
1996 }
1997 } else {
1998 // byte address buffers have no explicit type.
1999 TType uintType(EbtUint, storage);
2000 templateType->shallowCopy(uintType);
2001 }
2002
2003 // Create an unsized array out of that type.
2004 // TODO: does this work if it's already an array type?
2005 TArraySizes unsizedArray;
2006 unsizedArray.addInnerSize(UnsizedArraySize);
2007 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002008 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002009
2010 // field name is canonical for all structbuffers
2011 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002012
2013 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07002014
steve-lunarg5da1f032017-02-12 17:50:28 -07002015 TTypeList* blockStruct = new TTypeList;
2016 TTypeLoc member = { templateType, token.loc };
2017 blockStruct->push_back(member);
2018
steve-lunargdd8287a2017-02-23 18:04:12 -07002019 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002020 TType blockType(blockStruct, "", templateType->getQualifier());
2021
steve-lunargdd8287a2017-02-23 18:04:12 -07002022 blockType.getQualifier().storage = storage;
2023 blockType.getQualifier().readonly = readonly;
2024
2025 // We may have created an equivalent type before, in which case we should use its
2026 // deep structure.
2027 parseContext.shareStructBufferType(blockType);
2028
steve-lunarg5da1f032017-02-12 17:50:28 -07002029 type.shallowCopy(blockType);
2030
2031 return true;
2032}
2033
John Kesseniche6e74942016-06-11 16:43:14 -06002034// struct_declaration_list
2035// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2036//
2037// struct_declaration
2038// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002039// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002040//
2041// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002042// : IDENTIFIER post_decls
2043// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002044// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002045//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002046bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002047 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002048{
2049 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002050 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002051
2052 do {
2053 // success on seeing the RIGHT_BRACE coming up
2054 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002055 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002056
2057 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002058
2059 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002060
2061 // fully_specified_type
2062 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002063 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002064 expected("member type");
2065 return false;
2066 }
2067
2068 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002069 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002070 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002071 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002072 expected("member name");
2073 return false;
2074 }
2075
John Kessenich54ee28f2017-03-11 14:13:00 -07002076 if (peekTokenClass(EHTokLeftParen)) {
2077 // function_parameters
2078 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002079 declarators.resize(declarators.size() + 1);
2080 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002081 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2082 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002083 if (functionDefinitionAccepted)
2084 break;
2085 }
2086 expected("member-function definition");
2087 return false;
2088 } else {
2089 // add it to the list of members
2090 TTypeLoc member = { new TType(EbtVoid), token.loc };
2091 member.type->shallowCopy(memberType);
2092 member.type->setFieldName(*idToken.string);
2093 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002094
John Kessenich54ee28f2017-03-11 14:13:00 -07002095 // array_specifier
2096 TArraySizes* arraySizes = nullptr;
2097 acceptArraySpecifier(arraySizes);
2098 if (arraySizes)
2099 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002100
John Kessenich54ee28f2017-03-11 14:13:00 -07002101 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002102
John Kessenich54ee28f2017-03-11 14:13:00 -07002103 // EQUAL assignment_expression
2104 if (acceptTokenClass(EHTokAssign)) {
2105 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2106 TIntermTyped* expressionNode = nullptr;
2107 if (! acceptAssignmentExpression(expressionNode)) {
2108 expected("initializer");
2109 return false;
2110 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002111 }
2112 }
John Kesseniche6e74942016-06-11 16:43:14 -06002113 // success on seeing the SEMICOLON coming up
2114 if (peekTokenClass(EHTokSemicolon))
2115 break;
2116
2117 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002118 if (acceptTokenClass(EHTokComma))
2119 declarator_list = true;
2120 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002121 expected(",");
2122 return false;
2123 }
2124
2125 } while (true);
2126
2127 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002128 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002129 expected(";");
2130 return false;
2131 }
2132
2133 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002134
John Kessenichb16f7e62017-03-11 19:32:47 -07002135 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002136}
2137
John Kessenich54ee28f2017-03-11 14:13:00 -07002138// member_function_definition
2139// | function_parameters post_decls compound_statement
2140//
2141// Expects type to have EvqGlobal for a static member and
2142// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002143bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2144 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002145{
John Kessenich54ee28f2017-03-11 14:13:00 -07002146 bool accepted = false;
2147
John Kessenich4dc835c2017-03-28 23:43:10 -06002148 const TString* functionName = &memberName;
2149 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002150 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002151 if (type.getQualifier().storage == EvqTemporary)
2152 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002153 else
2154 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002155
2156 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002157 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002158 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002159 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002160
2161 // compound_statement (function body definition)
2162 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002163 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002164 declarator.body = new TVector<HlslToken>;
2165 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002166 }
2167 } else
2168 expected("function parameter list");
2169
John Kessenich54ee28f2017-03-11 14:13:00 -07002170 return accepted;
2171}
2172
John Kessenich5f934b02016-03-13 17:58:25 -06002173// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002174// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002175// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002176//
2177bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2178{
John Kessenich078d7f22016-03-14 10:02:11 -06002179 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002180 if (! acceptTokenClass(EHTokLeftParen))
2181 return false;
2182
John Kessenich71351de2016-06-08 12:50:56 -06002183 // VOID RIGHT_PAREN
2184 if (! acceptTokenClass(EHTokVoid)) {
2185 do {
2186 // parameter_declaration
2187 if (! acceptParameterDeclaration(function))
2188 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002189
John Kessenich71351de2016-06-08 12:50:56 -06002190 // COMMA
2191 if (! acceptTokenClass(EHTokComma))
2192 break;
2193 } while (true);
2194 }
John Kessenich5f934b02016-03-13 17:58:25 -06002195
John Kessenich078d7f22016-03-14 10:02:11 -06002196 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002197 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002198 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002199 return false;
2200 }
2201
2202 return true;
2203}
2204
steve-lunarg26d31452016-12-23 18:56:57 -07002205// default_parameter_declaration
2206// : EQUAL conditional_expression
2207// : EQUAL initializer
2208bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2209{
2210 node = nullptr;
2211
2212 // Valid not to have a default_parameter_declaration
2213 if (!acceptTokenClass(EHTokAssign))
2214 return true;
2215
2216 if (!acceptConditionalExpression(node)) {
2217 if (!acceptInitializer(node))
2218 return false;
2219
2220 // For initializer lists, we have to const-fold into a constructor for the type, so build
2221 // that.
John Kessenichc633f642017-04-03 21:48:37 -06002222 TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
steve-lunarg26d31452016-12-23 18:56:57 -07002223 if (constructor == nullptr) // cannot construct
2224 return false;
2225
2226 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002227 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002228 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002229
steve-lunarg26d31452016-12-23 18:56:57 -07002230 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2231 }
2232
2233 // If this is simply a constant, we can use it directly.
2234 if (node->getAsConstantUnion())
2235 return true;
2236
2237 // Otherwise, it has to be const-foldable.
2238 TIntermTyped* origNode = node;
2239
2240 node = intermediate.fold(node->getAsAggregate());
2241
2242 if (node != nullptr && origNode != node)
2243 return true;
2244
2245 parseContext.error(token.loc, "invalid default parameter value", "", "");
2246
2247 return false;
2248}
2249
John Kessenich5f934b02016-03-13 17:58:25 -06002250// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002251// : fully_specified_type post_decls [ = default_parameter_declaration ]
2252// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002253//
2254bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2255{
2256 // fully_specified_type
2257 TType* type = new TType;
2258 if (! acceptFullySpecifiedType(*type))
2259 return false;
2260
2261 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002262 HlslToken idToken;
2263 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002264
John Kessenich19b92ff2016-06-19 11:50:34 -06002265 // array_specifier
2266 TArraySizes* arraySizes = nullptr;
2267 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002268 if (arraySizes) {
2269 if (arraySizes->isImplicit()) {
2270 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2271 return false;
2272 }
2273
John Kessenich19b92ff2016-06-19 11:50:34 -06002274 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002275 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002276
2277 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002278 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002279
steve-lunarg26d31452016-12-23 18:56:57 -07002280 TIntermTyped* defaultValue;
2281 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2282 return false;
2283
John Kessenich5aa59e22016-06-17 15:50:47 -06002284 parseContext.paramFix(*type);
2285
steve-lunarg26d31452016-12-23 18:56:57 -07002286 // If any prior parameters have default values, all the parameters after that must as well.
2287 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2288 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2289 return false;
2290 }
2291
2292 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002293 function.addParameter(param);
2294
2295 return true;
2296}
2297
2298// Do the work to create the function definition in addition to
2299// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002300//
2301// If 'deferredTokens' are passed in, just get the token stream,
2302// don't process.
2303//
2304bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2305 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002306{
John Kessenich088d52b2017-03-11 17:55:28 -07002307 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002308
John Kessenichb16f7e62017-03-11 19:32:47 -07002309 if (deferredTokens)
2310 return captureBlockTokens(*deferredTokens);
2311 else
John Kessenich4960baa2017-03-19 18:09:59 -06002312 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002313}
2314
2315bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2316{
2317 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002318 TIntermNode* entryPointNode = nullptr;
2319
John Kessenich077e0522016-06-09 02:02:17 -06002320 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002321 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2322 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002323
2324 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002325 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002326 if (! acceptCompoundStatement(functionBody))
2327 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002328
John Kessenich54ee28f2017-03-11 14:13:00 -07002329 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002330 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002331
2332 // Hook up the 1 or 2 function definitions.
2333 nodeList = intermediate.growAggregate(nodeList, functionNode);
2334 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002335
2336 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002337}
2338
John Kessenich0d2b6de2016-06-05 11:23:11 -06002339// Accept an expression with parenthesis around it, where
2340// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002341// syntactically required ones like in "if ( expression )".
2342//
2343// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002344//
2345// Note this one is not set up to be speculative; as it gives
2346// errors if not found.
2347//
2348bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2349{
2350 // LEFT_PAREN
2351 if (! acceptTokenClass(EHTokLeftParen))
2352 expected("(");
2353
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002354 bool decl = false;
2355 TIntermNode* declNode = nullptr;
2356 decl = acceptControlDeclaration(declNode);
2357 if (decl) {
2358 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2359 expected("initialized declaration");
2360 return false;
2361 } else
2362 expression = declNode->getAsTyped();
2363 } else {
2364 // no declaration
2365 if (! acceptExpression(expression)) {
2366 expected("expression");
2367 return false;
2368 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002369 }
2370
2371 // RIGHT_PAREN
2372 if (! acceptTokenClass(EHTokRightParen))
2373 expected(")");
2374
2375 return true;
2376}
2377
John Kessenich34fb0362016-05-03 23:17:20 -06002378// The top-level full expression recognizer.
2379//
John Kessenich87142c72016-03-12 20:24:24 -07002380// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002381// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002382//
2383bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2384{
LoopDawgef764a22016-06-03 09:17:51 -06002385 node = nullptr;
2386
John Kessenich34fb0362016-05-03 23:17:20 -06002387 // assignment_expression
2388 if (! acceptAssignmentExpression(node))
2389 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002390
John Kessenich34fb0362016-05-03 23:17:20 -06002391 if (! peekTokenClass(EHTokComma))
2392 return true;
2393
2394 do {
2395 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002396 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002397 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002398
John Kessenich34fb0362016-05-03 23:17:20 -06002399 // ... assignment_expression
2400 TIntermTyped* rightNode = nullptr;
2401 if (! acceptAssignmentExpression(rightNode)) {
2402 expected("assignment expression");
2403 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002404 }
2405
John Kessenich34fb0362016-05-03 23:17:20 -06002406 node = intermediate.addComma(node, rightNode, loc);
2407
2408 if (! peekTokenClass(EHTokComma))
2409 return true;
2410 } while (true);
2411}
2412
John Kessenich07354242016-07-01 19:58:06 -06002413// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002414// : LEFT_BRACE RIGHT_BRACE
2415// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002416//
2417// initializer_list
2418// : assignment_expression COMMA assignment_expression COMMA ...
2419//
2420bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2421{
2422 // LEFT_BRACE
2423 if (! acceptTokenClass(EHTokLeftBrace))
2424 return false;
2425
John Kessenich98ad4852016-11-27 17:39:07 -07002426 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002427 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002428 if (acceptTokenClass(EHTokRightBrace)) {
2429 // a zero-length initializer list
2430 node = intermediate.makeAggregate(loc);
2431 return true;
2432 }
2433
2434 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002435 node = nullptr;
2436 do {
2437 // assignment_expression
2438 TIntermTyped* expr;
2439 if (! acceptAssignmentExpression(expr)) {
2440 expected("assignment expression in initializer list");
2441 return false;
2442 }
2443 node = intermediate.growAggregate(node, expr, loc);
2444
2445 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002446 if (acceptTokenClass(EHTokComma)) {
2447 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2448 return true;
John Kessenich07354242016-07-01 19:58:06 -06002449 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002450 }
John Kessenich07354242016-07-01 19:58:06 -06002451
2452 // RIGHT_BRACE
2453 if (acceptTokenClass(EHTokRightBrace))
2454 return true;
2455
2456 expected(", or }");
2457 return false;
2458 } while (true);
2459}
2460
John Kessenich34fb0362016-05-03 23:17:20 -06002461// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002462// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002463//
2464// a op (b op (c op d))
2465//
2466// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002467// : initializer
2468// | conditional_expression
2469// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002470//
2471bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2472{
John Kessenich07354242016-07-01 19:58:06 -06002473 // initializer
2474 if (peekTokenClass(EHTokLeftBrace)) {
2475 if (acceptInitializer(node))
2476 return true;
2477
2478 expected("initializer");
2479 return false;
2480 }
2481
John Kessenich00957f82016-07-27 10:39:57 -06002482 // conditional_expression
2483 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002484 return false;
2485
John Kessenich07354242016-07-01 19:58:06 -06002486 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002487 TOperator assignOp = HlslOpMap::assignment(peek());
2488 if (assignOp == EOpNull)
2489 return true;
2490
John Kessenich00957f82016-07-27 10:39:57 -06002491 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002492 TSourceLoc loc = token.loc;
2493 advanceToken();
2494
John Kessenich00957f82016-07-27 10:39:57 -06002495 // conditional_expression assign_op conditional_expression ...
2496 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002497 // gets the right-to-left associativity.
2498 TIntermTyped* rightNode = nullptr;
2499 if (! acceptAssignmentExpression(rightNode)) {
2500 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002501 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002502 }
2503
John Kessenichd21baed2016-09-16 03:05:12 -06002504 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002505 node = parseContext.handleLvalue(loc, "assign", node);
2506
John Kessenichfea226b2016-07-28 17:53:56 -06002507 if (node == nullptr) {
2508 parseContext.error(loc, "could not create assignment", "", "");
2509 return false;
2510 }
John Kessenich34fb0362016-05-03 23:17:20 -06002511
2512 if (! peekTokenClass(EHTokComma))
2513 return true;
2514
2515 return true;
2516}
2517
John Kessenich00957f82016-07-27 10:39:57 -06002518// Accept a conditional expression, which associates right-to-left,
2519// accomplished by the "true" expression calling down to lower
2520// precedence levels than this level.
2521//
2522// conditional_expression
2523// : binary_expression
2524// | binary_expression QUESTION expression COLON assignment_expression
2525//
2526bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2527{
2528 // binary_expression
2529 if (! acceptBinaryExpression(node, PlLogicalOr))
2530 return false;
2531
2532 if (! acceptTokenClass(EHTokQuestion))
2533 return true;
2534
John Kessenich7e997e22017-03-30 22:09:30 -06002535 node = parseContext.convertConditionalExpression(token.loc, node);
2536 if (node == nullptr)
2537 return false;
2538
John Kessenich00957f82016-07-27 10:39:57 -06002539 TIntermTyped* trueNode = nullptr;
2540 if (! acceptExpression(trueNode)) {
2541 expected("expression after ?");
2542 return false;
2543 }
2544 TSourceLoc loc = token.loc;
2545
2546 if (! acceptTokenClass(EHTokColon)) {
2547 expected(":");
2548 return false;
2549 }
2550
2551 TIntermTyped* falseNode = nullptr;
2552 if (! acceptAssignmentExpression(falseNode)) {
2553 expected("expression after :");
2554 return false;
2555 }
2556
2557 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2558
2559 return true;
2560}
2561
John Kessenich34fb0362016-05-03 23:17:20 -06002562// Accept a binary expression, for binary operations that
2563// associate left-to-right. This is, it is implicit, for example
2564//
2565// ((a op b) op c) op d
2566//
2567// binary_expression
2568// : expression op expression op expression ...
2569//
2570// where 'expression' is the next higher level in precedence.
2571//
2572bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2573{
2574 if (precedenceLevel > PlMul)
2575 return acceptUnaryExpression(node);
2576
2577 // assignment_expression
2578 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2579 return false;
2580
John Kessenich34fb0362016-05-03 23:17:20 -06002581 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002582 TOperator op = HlslOpMap::binary(peek());
2583 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2584 if (tokenLevel < precedenceLevel)
2585 return true;
2586
John Kessenich34fb0362016-05-03 23:17:20 -06002587 // ... op
2588 TSourceLoc loc = token.loc;
2589 advanceToken();
2590
2591 // ... expression
2592 TIntermTyped* rightNode = nullptr;
2593 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2594 expected("expression");
2595 return false;
2596 }
2597
2598 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002599 if (node == nullptr) {
2600 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2601 return false;
2602 }
John Kessenich34fb0362016-05-03 23:17:20 -06002603 } while (true);
2604}
2605
2606// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002607// : (type) unary_expression
2608// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002609// | - unary_expression
2610// | ! unary_expression
2611// | ~ unary_expression
2612// | ++ unary_expression
2613// | -- unary_expression
2614// | postfix_expression
2615//
2616bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2617{
John Kessenich1cc1a282016-06-03 16:55:49 -06002618 // (type) unary_expression
2619 // Have to look two steps ahead, because this could be, e.g., a
2620 // postfix_expression instead, since that also starts with at "(".
2621 if (acceptTokenClass(EHTokLeftParen)) {
2622 TType castType;
2623 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002624 if (acceptTokenClass(EHTokRightParen)) {
2625 // We've matched "(type)" now, get the expression to cast
2626 TSourceLoc loc = token.loc;
2627 if (! acceptUnaryExpression(node))
2628 return false;
2629
2630 // Hook it up like a constructor
John Kessenichc633f642017-04-03 21:48:37 -06002631 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
steve-lunarg5964c642016-07-30 07:38:55 -06002632 if (constructorFunction == nullptr) {
2633 expected("type that can be constructed");
2634 return false;
2635 }
2636 TIntermTyped* arguments = nullptr;
2637 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2638 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2639
2640 return true;
2641 } else {
2642 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2643 // the '(int' part. We must back up twice.
2644 recedeToken();
2645 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002646 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002647 } else {
2648 // This isn't a type cast, but it still started "(", so if it is a
2649 // unary expression, it can only be a postfix_expression, so try that.
2650 // Back it up first.
2651 recedeToken();
2652 return acceptPostfixExpression(node);
2653 }
2654 }
2655
2656 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002657 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002658
John Kessenich1cc1a282016-06-03 16:55:49 -06002659 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002660 if (unaryOp == EOpNull)
2661 return acceptPostfixExpression(node);
2662
2663 // op unary_expression
2664 TSourceLoc loc = token.loc;
2665 advanceToken();
2666 if (! acceptUnaryExpression(node))
2667 return false;
2668
2669 // + is a no-op
2670 if (unaryOp == EOpAdd)
2671 return true;
2672
2673 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002674
2675 // These unary ops require lvalues
2676 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2677 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002678
2679 return node != nullptr;
2680}
2681
2682// postfix_expression
2683// : LEFT_PAREN expression RIGHT_PAREN
2684// | literal
2685// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002686// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002687// | function_call
2688// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2689// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002690// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002691// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002692// | postfix_expression INC_OP
2693// | postfix_expression DEC_OP
2694//
2695bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2696{
2697 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002698 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002699
2700 // idToken will pick up either a variable or a function name in a function call
2701 HlslToken idToken;
2702
John Kessenich21472ae2016-06-04 11:46:33 -06002703 // Find something before the postfix operations, as they can't operate
2704 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002705 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002706 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002707 if (! acceptExpression(node)) {
2708 expected("expression");
2709 return false;
2710 }
2711 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002712 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002713 return false;
2714 }
John Kessenich34fb0362016-05-03 23:17:20 -06002715 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002716 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002717 } else if (acceptConstructor(node)) {
2718 // constructor (nothing else to do yet)
2719 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002720 // user-type, namespace name, variable, or function name
2721 TString* fullName = idToken.string;
2722 while (acceptTokenClass(EHTokColonColon)) {
2723 // user-type or namespace name
2724 fullName = NewPoolTString(fullName->c_str());
2725 fullName->append(parseContext.scopeMangler);
2726 if (acceptIdentifier(idToken))
2727 fullName->append(*idToken.string);
2728 else {
2729 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002730 return false;
2731 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002732 }
2733 if (! peekTokenClass(EHTokLeftParen)) {
2734 node = parseContext.handleVariable(idToken.loc, fullName);
2735 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002736 // function_call (nothing else to do yet)
2737 } else {
2738 expected("function call arguments");
2739 return false;
2740 }
John Kessenich21472ae2016-06-04 11:46:33 -06002741 } else {
2742 // nothing found, can't post operate
2743 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002744 }
2745
steve-lunarga2b01a02016-11-28 17:09:54 -07002746 // This is to guarantee we do this no matter how we get out of the stack frame.
2747 // This way there's no bug if an early return forgets to do it.
2748 struct tFinalize {
2749 tFinalize(HlslParseContext& p) : parseContext(p) { }
2750 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002751 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002752 private:
John Kessenichca71d942017-03-07 20:44:09 -07002753 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002754 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002755 } finalize(parseContext);
2756
2757 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2758 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2759 // level: hence the init and finalize. Even though in practice these must be
2760 // constants, they are parsed no matter what.
2761 parseContext.initFlattening();
2762
John Kessenich21472ae2016-06-04 11:46:33 -06002763 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002764 do {
2765 TSourceLoc loc = token.loc;
2766 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002767
John Kessenich34fb0362016-05-03 23:17:20 -06002768 // Consume only a valid post-unary operator, otherwise we are done.
2769 switch (postOp) {
2770 case EOpIndexDirectStruct:
2771 case EOpIndexIndirect:
2772 case EOpPostIncrement:
2773 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002774 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002775 advanceToken();
2776 break;
2777 default:
2778 return true;
2779 }
John Kessenich87142c72016-03-12 20:24:24 -07002780
John Kessenich34fb0362016-05-03 23:17:20 -06002781 // We have a valid post-unary operator, process it.
2782 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002783 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002784 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002785 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002786 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002787 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002788 HlslToken field;
2789 if (! acceptIdentifier(field)) {
2790 expected("swizzle or member");
2791 return false;
2792 }
LoopDawg4886f692016-06-29 10:58:58 -06002793
John Kessenich516d92d2017-03-08 20:09:03 -07002794 if (peekTokenClass(EHTokLeftParen)) {
2795 // member function
2796 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002797
John Kessenich516d92d2017-03-08 20:09:03 -07002798 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002799 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002800 expected("function parameters");
2801 return false;
2802 }
John Kessenich516d92d2017-03-08 20:09:03 -07002803 } else
2804 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002805
John Kessenich34fb0362016-05-03 23:17:20 -06002806 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002807 }
John Kessenich34fb0362016-05-03 23:17:20 -06002808 case EOpIndexIndirect:
2809 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002810 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002811 TIntermTyped* indexNode = nullptr;
2812 if (! acceptExpression(indexNode) ||
2813 ! peekTokenClass(EHTokRightBracket)) {
2814 expected("expression followed by ']'");
2815 return false;
2816 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002817 advanceToken();
2818 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2819 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002820 }
2821 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002822 // INC_OP
2823 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002824 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002825 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002826 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002827 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002828 break;
2829 default:
2830 assert(0);
2831 break;
2832 }
2833 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002834}
2835
John Kessenichd016be12016-03-13 11:24:20 -06002836// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002837// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002838//
2839bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2840{
2841 // type
2842 TType type;
2843 if (acceptType(type)) {
John Kessenichc633f642017-04-03 21:48:37 -06002844 TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
John Kessenichd016be12016-03-13 11:24:20 -06002845 if (constructorFunction == nullptr)
2846 return false;
2847
2848 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002849 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002850 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002851 // It's possible this is a type keyword used as an identifier. Put the token back
2852 // for later use.
2853 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002854 return false;
2855 }
2856
2857 // hook it up
2858 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2859
2860 return true;
2861 }
2862
2863 return false;
2864}
2865
John Kessenich34fb0362016-05-03 23:17:20 -06002866// The function_call identifier was already recognized, and passed in as idToken.
2867//
2868// function_call
2869// : [idToken] arguments
2870//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002871bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002872{
John Kessenich54ee28f2017-03-11 14:13:00 -07002873 // name
2874 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002875 if (baseObject == nullptr) {
2876 functionName = &name;
2877 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002878 // Built-in methods are not in the symbol table as methods, but as global functions
2879 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002880 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002881 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002882 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002883 if (! baseObject->getType().isStruct()) {
2884 expected("structure");
2885 return false;
2886 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002887 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002888 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002889 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002890 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002891 }
LoopDawg4886f692016-06-29 10:58:58 -06002892
John Kessenich54ee28f2017-03-11 14:13:00 -07002893 // function
2894 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2895
2896 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002897 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002898 if (baseObject != nullptr) {
2899 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002900 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002901 }
John Kessenich4678ca92016-05-13 09:33:42 -06002902 if (! acceptArguments(function, arguments))
2903 return false;
2904
John Kessenich54ee28f2017-03-11 14:13:00 -07002905 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002906 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002907
2908 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002909}
2910
John Kessenich87142c72016-03-12 20:24:24 -07002911// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002912// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002913//
John Kessenichd016be12016-03-13 11:24:20 -06002914// The arguments are pushed onto the 'function' argument list and
2915// onto the 'arguments' aggregate.
2916//
John Kessenich4678ca92016-05-13 09:33:42 -06002917bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002918{
John Kessenich078d7f22016-03-14 10:02:11 -06002919 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002920 if (! acceptTokenClass(EHTokLeftParen))
2921 return false;
2922
2923 do {
John Kessenichd016be12016-03-13 11:24:20 -06002924 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002925 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002926 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002927 break;
John Kessenichd016be12016-03-13 11:24:20 -06002928
2929 // hook it up
2930 parseContext.handleFunctionArgument(function, arguments, arg);
2931
John Kessenich078d7f22016-03-14 10:02:11 -06002932 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002933 if (! acceptTokenClass(EHTokComma))
2934 break;
2935 } while (true);
2936
John Kessenich078d7f22016-03-14 10:02:11 -06002937 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002938 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002939 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002940 return false;
2941 }
2942
2943 return true;
2944}
2945
2946bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2947{
2948 switch (token.tokenClass) {
2949 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002950 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002951 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002952 case EHTokUintConstant:
2953 node = intermediate.addConstantUnion(token.u, token.loc, true);
2954 break;
John Kessenich87142c72016-03-12 20:24:24 -07002955 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002956 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002957 break;
2958 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002959 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002960 break;
2961 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002962 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002963 break;
John Kessenich86f71382016-09-19 20:23:18 -06002964 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002965 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002966 break;
John Kessenich87142c72016-03-12 20:24:24 -07002967
2968 default:
2969 return false;
2970 }
2971
2972 advanceToken();
2973
2974 return true;
2975}
2976
John Kessenich5f934b02016-03-13 17:58:25 -06002977// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002978// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002979//
John Kessenich21472ae2016-06-04 11:46:33 -06002980bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002981{
John Kessenich21472ae2016-06-04 11:46:33 -06002982 TIntermAggregate* compoundStatement = nullptr;
2983
John Kessenich34fb0362016-05-03 23:17:20 -06002984 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002985 if (! acceptTokenClass(EHTokLeftBrace))
2986 return false;
2987
2988 // statement statement ...
2989 TIntermNode* statement = nullptr;
2990 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002991 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2992 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2993 branch->getFlowOp() == EOpDefault)) {
2994 // hook up individual subsequences within a switch statement
2995 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2996 compoundStatement = nullptr;
2997 } else {
2998 // hook it up to the growing compound statement
2999 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3000 }
John Kessenich5f934b02016-03-13 17:58:25 -06003001 }
John Kessenich34fb0362016-05-03 23:17:20 -06003002 if (compoundStatement)
3003 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06003004
John Kessenich21472ae2016-06-04 11:46:33 -06003005 retStatement = compoundStatement;
3006
John Kessenich34fb0362016-05-03 23:17:20 -06003007 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003008 return acceptTokenClass(EHTokRightBrace);
3009}
3010
John Kessenich0d2b6de2016-06-05 11:23:11 -06003011bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3012{
3013 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003014 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003015 parseContext.popScope();
3016
3017 return result;
3018}
3019
John Kessenich077e0522016-06-09 02:02:17 -06003020bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003021{
John Kessenich077e0522016-06-09 02:02:17 -06003022 parseContext.pushScope();
3023 bool result = acceptCompoundStatement(statement);
3024 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003025
3026 return result;
3027}
3028
John Kessenich5f934b02016-03-13 17:58:25 -06003029// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003030// : attributes attributed_statement
3031//
3032// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003033// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003034// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06003035// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06003036// | declaration_statement
3037// | selection_statement
3038// | switch_statement
3039// | case_label
3040// | iteration_statement
3041// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003042//
3043bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3044{
John Kessenich21472ae2016-06-04 11:46:33 -06003045 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003046
John Kessenich21472ae2016-06-04 11:46:33 -06003047 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003048 TAttributeMap attributes;
3049 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003050
John Kessenich21472ae2016-06-04 11:46:33 -06003051 // attributed_statement
3052 switch (peek()) {
3053 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003054 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003055
John Kessenich21472ae2016-06-04 11:46:33 -06003056 case EHTokIf:
3057 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003058
John Kessenich21472ae2016-06-04 11:46:33 -06003059 case EHTokSwitch:
3060 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003061
John Kessenich21472ae2016-06-04 11:46:33 -06003062 case EHTokFor:
3063 case EHTokDo:
3064 case EHTokWhile:
3065 return acceptIterationStatement(statement);
3066
3067 case EHTokContinue:
3068 case EHTokBreak:
3069 case EHTokDiscard:
3070 case EHTokReturn:
3071 return acceptJumpStatement(statement);
3072
3073 case EHTokCase:
3074 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003075 case EHTokDefault:
3076 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003077
3078 case EHTokSemicolon:
3079 return acceptTokenClass(EHTokSemicolon);
3080
3081 case EHTokRightBrace:
3082 // Performance: not strictly necessary, but stops a bunch of hunting early,
3083 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003084 return false;
3085
John Kessenich21472ae2016-06-04 11:46:33 -06003086 default:
3087 {
3088 // declaration
3089 if (acceptDeclaration(statement))
3090 return true;
3091
3092 // expression
3093 TIntermTyped* node;
3094 if (acceptExpression(node))
3095 statement = node;
3096 else
3097 return false;
3098
3099 // SEMICOLON (following an expression)
3100 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003101 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003102 return false;
3103 }
3104 }
3105 }
3106
John Kessenich5f934b02016-03-13 17:58:25 -06003107 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003108}
3109
John Kessenich21472ae2016-06-04 11:46:33 -06003110// attributes
3111// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3112//
3113// attribute:
3114// : UNROLL
3115// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3116// | FASTOPT
3117// | ALLOW_UAV_CONDITION
3118// | BRANCH
3119// | FLATTEN
3120// | FORCECASE
3121// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003122// | DOMAIN
3123// | EARLYDEPTHSTENCIL
3124// | INSTANCE
3125// | MAXTESSFACTOR
3126// | OUTPUTCONTROLPOINTS
3127// | OUTPUTTOPOLOGY
3128// | PARTITIONING
3129// | PATCHCONSTANTFUNC
3130// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003131//
steve-lunarg1868b142016-10-20 13:07:10 -06003132void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003133{
steve-lunarg1868b142016-10-20 13:07:10 -06003134 // For now, accept the [ XXX(X) ] syntax, but drop all but
3135 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003136 // TODO: subset to correct set? Pass on?
3137 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003138 HlslToken idToken;
3139
John Kessenich0d2b6de2016-06-05 11:23:11 -06003140 // LEFT_BRACKET?
3141 if (! acceptTokenClass(EHTokLeftBracket))
3142 return;
3143
3144 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003145 if (acceptIdentifier(idToken)) {
3146 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003147 } else if (! peekTokenClass(EHTokRightBracket)) {
3148 expected("identifier");
3149 advanceToken();
3150 }
3151
steve-lunarga22f7db2016-11-11 08:17:44 -07003152 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003153
3154 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003155 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003156 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003157
John Kessenich0d2b6de2016-06-05 11:23:11 -06003158 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003159 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003160
steve-lunarga22f7db2016-11-11 08:17:44 -07003161 while (acceptAssignmentExpression(node)) {
3162 expectingExpression = false;
3163 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003164 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003165 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003166 }
3167
steve-lunarga22f7db2016-11-11 08:17:44 -07003168 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003169 if (! acceptTokenClass(EHTokRightParen))
3170 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003171
3172 // Error for partial or missing expression
3173 if (expectingExpression || expressions->getSequence().empty())
3174 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003175 }
3176
3177 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003178 if (!acceptTokenClass(EHTokRightBracket)) {
3179 expected("]");
3180 return;
3181 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003182
steve-lunarg1868b142016-10-20 13:07:10 -06003183 // Add any values we found into the attribute map. This accepts
3184 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003185 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003186 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003187}
3188
John Kessenich0d2b6de2016-06-05 11:23:11 -06003189// selection_statement
3190// : IF LEFT_PAREN expression RIGHT_PAREN statement
3191// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3192//
John Kessenich21472ae2016-06-04 11:46:33 -06003193bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3194{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003195 TSourceLoc loc = token.loc;
3196
3197 // IF
3198 if (! acceptTokenClass(EHTokIf))
3199 return false;
3200
3201 // so that something declared in the condition is scoped to the lifetimes
3202 // of the then-else statements
3203 parseContext.pushScope();
3204
3205 // LEFT_PAREN expression RIGHT_PAREN
3206 TIntermTyped* condition;
3207 if (! acceptParenExpression(condition))
3208 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003209 condition = parseContext.convertConditionalExpression(loc, condition);
3210 if (condition == nullptr)
3211 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003212
3213 // create the child statements
3214 TIntermNodePair thenElse = { nullptr, nullptr };
3215
3216 // then statement
3217 if (! acceptScopedStatement(thenElse.node1)) {
3218 expected("then statement");
3219 return false;
3220 }
3221
3222 // ELSE
3223 if (acceptTokenClass(EHTokElse)) {
3224 // else statement
3225 if (! acceptScopedStatement(thenElse.node2)) {
3226 expected("else statement");
3227 return false;
3228 }
3229 }
3230
3231 // Put the pieces together
3232 statement = intermediate.addSelection(condition, thenElse, loc);
3233 parseContext.popScope();
3234
3235 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003236}
3237
John Kessenichd02dc5d2016-07-01 00:04:11 -06003238// switch_statement
3239// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3240//
John Kessenich21472ae2016-06-04 11:46:33 -06003241bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3242{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003243 // SWITCH
3244 TSourceLoc loc = token.loc;
3245 if (! acceptTokenClass(EHTokSwitch))
3246 return false;
3247
3248 // LEFT_PAREN expression RIGHT_PAREN
3249 parseContext.pushScope();
3250 TIntermTyped* switchExpression;
3251 if (! acceptParenExpression(switchExpression)) {
3252 parseContext.popScope();
3253 return false;
3254 }
3255
3256 // compound_statement
3257 parseContext.pushSwitchSequence(new TIntermSequence);
3258 bool statementOkay = acceptCompoundStatement(statement);
3259 if (statementOkay)
3260 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3261
3262 parseContext.popSwitchSequence();
3263 parseContext.popScope();
3264
3265 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003266}
3267
John Kessenich119f8f62016-06-05 15:44:07 -06003268// iteration_statement
3269// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3270// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3271// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3272//
3273// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003274bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3275{
John Kessenich119f8f62016-06-05 15:44:07 -06003276 TSourceLoc loc = token.loc;
3277 TIntermTyped* condition = nullptr;
3278
3279 EHlslTokenClass loop = peek();
3280 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3281
3282 // WHILE or DO or FOR
3283 advanceToken();
3284
3285 switch (loop) {
3286 case EHTokWhile:
3287 // so that something declared in the condition is scoped to the lifetime
3288 // of the while sub-statement
3289 parseContext.pushScope();
3290 parseContext.nestLooping();
3291
3292 // LEFT_PAREN condition RIGHT_PAREN
3293 if (! acceptParenExpression(condition))
3294 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003295 condition = parseContext.convertConditionalExpression(loc, condition);
3296 if (condition == nullptr)
3297 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003298
3299 // statement
3300 if (! acceptScopedStatement(statement)) {
3301 expected("while sub-statement");
3302 return false;
3303 }
3304
3305 parseContext.unnestLooping();
3306 parseContext.popScope();
3307
3308 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3309
3310 return true;
3311
3312 case EHTokDo:
3313 parseContext.nestLooping();
3314
3315 if (! acceptTokenClass(EHTokLeftBrace))
3316 expected("{");
3317
3318 // statement
3319 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3320 expected("do sub-statement");
3321 return false;
3322 }
3323
3324 if (! acceptTokenClass(EHTokRightBrace))
3325 expected("}");
3326
3327 // WHILE
3328 if (! acceptTokenClass(EHTokWhile)) {
3329 expected("while");
3330 return false;
3331 }
3332
3333 // LEFT_PAREN condition RIGHT_PAREN
3334 TIntermTyped* condition;
3335 if (! acceptParenExpression(condition))
3336 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003337 condition = parseContext.convertConditionalExpression(loc, condition);
3338 if (condition == nullptr)
3339 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003340
3341 if (! acceptTokenClass(EHTokSemicolon))
3342 expected(";");
3343
3344 parseContext.unnestLooping();
3345
3346 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3347
3348 return true;
3349
3350 case EHTokFor:
3351 {
3352 // LEFT_PAREN
3353 if (! acceptTokenClass(EHTokLeftParen))
3354 expected("(");
3355
3356 // so that something declared in the condition is scoped to the lifetime
3357 // of the for sub-statement
3358 parseContext.pushScope();
3359
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003360 // initializer
3361 TIntermNode* initNode = nullptr;
3362 if (! acceptControlDeclaration(initNode)) {
3363 TIntermTyped* initExpr = nullptr;
3364 acceptExpression(initExpr);
3365 initNode = initExpr;
3366 }
3367 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003368 if (! acceptTokenClass(EHTokSemicolon))
3369 expected(";");
3370
3371 parseContext.nestLooping();
3372
3373 // condition SEMI_COLON
3374 acceptExpression(condition);
3375 if (! acceptTokenClass(EHTokSemicolon))
3376 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003377 if (condition != nullptr) {
3378 condition = parseContext.convertConditionalExpression(loc, condition);
3379 if (condition == nullptr)
3380 return false;
3381 }
John Kessenich119f8f62016-06-05 15:44:07 -06003382
3383 // iterator SEMI_COLON
3384 TIntermTyped* iterator = nullptr;
3385 acceptExpression(iterator);
3386 if (! acceptTokenClass(EHTokRightParen))
3387 expected(")");
3388
3389 // statement
3390 if (! acceptScopedStatement(statement)) {
3391 expected("for sub-statement");
3392 return false;
3393 }
3394
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003395 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003396
3397 parseContext.popScope();
3398 parseContext.unnestLooping();
3399
3400 return true;
3401 }
3402
3403 default:
3404 return false;
3405 }
John Kessenich21472ae2016-06-04 11:46:33 -06003406}
3407
3408// jump_statement
3409// : CONTINUE SEMICOLON
3410// | BREAK SEMICOLON
3411// | DISCARD SEMICOLON
3412// | RETURN SEMICOLON
3413// | RETURN expression SEMICOLON
3414//
3415bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3416{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003417 EHlslTokenClass jump = peek();
3418 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003419 case EHTokContinue:
3420 case EHTokBreak:
3421 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003422 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003423 advanceToken();
3424 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003425 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003426 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003427 return false;
3428 }
John Kessenich21472ae2016-06-04 11:46:33 -06003429
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003430 switch (jump) {
3431 case EHTokContinue:
3432 statement = intermediate.addBranch(EOpContinue, token.loc);
3433 break;
3434 case EHTokBreak:
3435 statement = intermediate.addBranch(EOpBreak, token.loc);
3436 break;
3437 case EHTokDiscard:
3438 statement = intermediate.addBranch(EOpKill, token.loc);
3439 break;
3440
3441 case EHTokReturn:
3442 {
3443 // expression
3444 TIntermTyped* node;
3445 if (acceptExpression(node)) {
3446 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003447 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003448 } else
3449 statement = intermediate.addBranch(EOpReturn, token.loc);
3450 break;
3451 }
3452
3453 default:
3454 assert(0);
3455 return false;
3456 }
3457
3458 // SEMICOLON
3459 if (! acceptTokenClass(EHTokSemicolon))
3460 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003461
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003462 return true;
3463}
John Kessenich21472ae2016-06-04 11:46:33 -06003464
John Kessenichd02dc5d2016-07-01 00:04:11 -06003465// case_label
3466// : CASE expression COLON
3467//
John Kessenich21472ae2016-06-04 11:46:33 -06003468bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3469{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003470 TSourceLoc loc = token.loc;
3471 if (! acceptTokenClass(EHTokCase))
3472 return false;
3473
3474 TIntermTyped* expression;
3475 if (! acceptExpression(expression)) {
3476 expected("case expression");
3477 return false;
3478 }
3479
3480 if (! acceptTokenClass(EHTokColon)) {
3481 expected(":");
3482 return false;
3483 }
3484
3485 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3486
3487 return true;
3488}
3489
3490// default_label
3491// : DEFAULT COLON
3492//
3493bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3494{
3495 TSourceLoc loc = token.loc;
3496 if (! acceptTokenClass(EHTokDefault))
3497 return false;
3498
3499 if (! acceptTokenClass(EHTokColon)) {
3500 expected(":");
3501 return false;
3502 }
3503
3504 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3505
3506 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003507}
3508
John Kessenich19b92ff2016-06-19 11:50:34 -06003509// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003510// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3511// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003512//
3513void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3514{
3515 arraySizes = nullptr;
3516
steve-lunarg7b211a32016-10-13 12:26:18 -06003517 // Early-out if there aren't any array dimensions
3518 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003519 return;
3520
steve-lunarg7b211a32016-10-13 12:26:18 -06003521 // 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 -06003522 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003523
3524 // Collect each array dimension.
3525 while (acceptTokenClass(EHTokLeftBracket)) {
3526 TSourceLoc loc = token.loc;
3527 TIntermTyped* sizeExpr = nullptr;
3528
John Kessenich057df292017-03-06 18:18:37 -07003529 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003530 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3531
3532 if (! acceptTokenClass(EHTokRightBracket)) {
3533 expected("]");
3534 return;
3535 }
3536
3537 if (hasArraySize) {
3538 TArraySize arraySize;
3539 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3540 arraySizes->addInnerSize(arraySize);
3541 } else {
3542 arraySizes->addInnerSize(0); // sized by initializers.
3543 }
steve-lunarg265c0612016-09-27 10:57:35 -06003544 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003545}
3546
John Kessenich630dd7d2016-06-12 23:52:12 -06003547// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003548// : COLON semantic // optional
3549// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3550// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003551// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003552// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003553//
John Kessenich854fe242017-03-02 14:30:59 -07003554// Return true if any tokens were accepted. That is,
3555// false can be returned on successfully recognizing nothing,
3556// not necessarily meaning bad syntax.
3557//
3558bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003559{
John Kessenich854fe242017-03-02 14:30:59 -07003560 bool found = false;
3561
John Kessenich630dd7d2016-06-12 23:52:12 -06003562 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003563 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003564 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003565 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003566 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003567 if (peekTokenClass(EHTokLayout))
3568 acceptLayoutQualifierList(qualifier);
3569 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003570 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003571 if (! acceptTokenClass(EHTokLeftParen)) {
3572 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003573 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003574 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003575 HlslToken locationToken;
3576 if (! acceptIdentifier(locationToken)) {
3577 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003578 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003579 }
3580 HlslToken componentToken;
3581 if (acceptTokenClass(EHTokDot)) {
3582 if (! acceptIdentifier(componentToken)) {
3583 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003584 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003585 }
3586 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003587 if (! acceptTokenClass(EHTokRightParen)) {
3588 expected(")");
3589 break;
3590 }
John Kessenich7735b942016-09-05 12:40:06 -06003591 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003592 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003593 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003594 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003595 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003596 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3597 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003598 if (! acceptTokenClass(EHTokLeftParen)) {
3599 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003600 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003601 }
John Kessenichb38f0712016-07-30 10:29:54 -06003602 HlslToken registerDesc; // for Type#
3603 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003604 if (! acceptIdentifier(registerDesc)) {
3605 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003606 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003607 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003608 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3609 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003610 // Then we didn't really see the registerDesc yet, it was
3611 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003612 profile = registerDesc;
3613 if (! acceptIdentifier(registerDesc)) {
3614 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003615 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003616 }
3617 }
John Kessenichb38f0712016-07-30 10:29:54 -06003618 int subComponent = 0;
3619 if (acceptTokenClass(EHTokLeftBracket)) {
3620 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3621 if (! peekTokenClass(EHTokIntConstant)) {
3622 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003623 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003624 }
3625 subComponent = token.i;
3626 advanceToken();
3627 if (! acceptTokenClass(EHTokRightBracket)) {
3628 expected("]");
3629 break;
3630 }
3631 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003632 // (COMMA SPACEN)opt
3633 HlslToken spaceDesc;
3634 if (acceptTokenClass(EHTokComma)) {
3635 if (! acceptIdentifier(spaceDesc)) {
3636 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003637 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003638 }
3639 }
3640 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003641 if (! acceptTokenClass(EHTokRightParen)) {
3642 expected(")");
3643 break;
3644 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003645 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003646 } else {
3647 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003648 TString semanticUpperCase = *idToken.string;
3649 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3650 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003651 }
John Kessenich854fe242017-03-02 14:30:59 -07003652 } else if (peekTokenClass(EHTokLeftAngle)) {
3653 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003654 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003655 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003656 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003657
John Kessenich630dd7d2016-06-12 23:52:12 -06003658 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003659
3660 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003661}
3662
John Kessenichb16f7e62017-03-11 19:32:47 -07003663//
3664// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3665// processing.
3666//
3667bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3668{
3669 if (! peekTokenClass(EHTokLeftBrace))
3670 return false;
3671
3672 int braceCount = 0;
3673
3674 do {
3675 switch (peek()) {
3676 case EHTokLeftBrace:
3677 ++braceCount;
3678 break;
3679 case EHTokRightBrace:
3680 --braceCount;
3681 break;
3682 case EHTokNone:
3683 // End of input before balance { } is bad...
3684 return false;
3685 default:
3686 break;
3687 }
3688
3689 tokens.push_back(token);
3690 advanceToken();
3691 } while (braceCount > 0);
3692
3693 return true;
3694}
3695
John Kesseniche01a9bc2016-03-12 20:11:22 -07003696} // end namespace glslang