blob: 32b1de3513ebde5ad78dbd70528c77f69be45934 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2016 Google, Inc.
3// Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kesseniche01a9bc2016-03-12 20:11:22 -07006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kesseniche01a9bc2016-03-12 20:11:22 -070010//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of Google, Inc., nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
John Kessenich927608b2017-01-06 12:34:14 -070023// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
John Kesseniche01a9bc2016-03-12 20:11:22 -070035//
36
John Kessenichd016be12016-03-13 11:24:20 -060037//
38// This is a set of mutually recursive methods implementing the HLSL grammar.
39// Generally, each returns
40// - through an argument: a type specifically appropriate to which rule it
41// recognized
42// - through the return value: true/false to indicate whether or not it
43// recognized its rule
44//
45// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060046// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060047// will build the AST.
48//
49// The next token, yet to be "accepted" is always sitting in 'token'.
50// When a method says it accepts a rule, that means all tokens involved
51// in the rule will have been consumed, and none left in 'token'.
52//
53
John Kesseniche01a9bc2016-03-12 20:11:22 -070054#include "hlslTokens.h"
55#include "hlslGrammar.h"
steve-lunarg1868b142016-10-20 13:07:10 -060056#include "hlslAttributes.h"
John Kesseniche01a9bc2016-03-12 20:11:22 -070057
58namespace glslang {
59
60// Root entry point to this recursive decent parser.
61// Return true if compilation unit was successfully accepted.
62bool HlslGrammar::parse()
63{
64 advanceToken();
65 return acceptCompilationUnit();
66}
67
68void HlslGrammar::expected(const char* syntax)
69{
70 parseContext.error(token.loc, "Expected", syntax, "");
71}
72
LoopDawg4886f692016-06-29 10:58:58 -060073void HlslGrammar::unimplemented(const char* error)
74{
75 parseContext.error(token.loc, "Unimplemented", error, "");
76}
77
John Kessenich7a41f962017-03-22 11:38:22 -060078// IDENTIFIER
79// THIS
80// type that can be used as IDENTIFIER
81//
John Kessenichaecd4972016-03-14 10:46:34 -060082// Only process the next token if it is an identifier.
83// Return true if it was an identifier.
84bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
85{
John Kessenich7a41f962017-03-22 11:38:22 -060086 // IDENTIFIER
John Kessenichaecd4972016-03-14 10:46:34 -060087 if (peekTokenClass(EHTokIdentifier)) {
88 idToken = token;
89 advanceToken();
90 return true;
91 }
92
John Kessenich7a41f962017-03-22 11:38:22 -060093 // THIS
94 // -> maps to the IDENTIFIER spelled with the internal special name for 'this'
95 if (peekTokenClass(EHTokThis)) {
96 idToken = token;
97 advanceToken();
98 idToken.tokenClass = EHTokIdentifier;
99 idToken.string = NewPoolTString(intermediate.implicitThisName);
100 return true;
101 }
102
103 // type that can be used as IDENTIFIER
104
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700105 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
106 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
107 // valid identifier, nor is "linear". This code special cases the known instances of this, so
108 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
John Kessenichecba76f2017-01-06 00:34:48 -0700109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 TString* idString = nullptr;
111 switch (peek()) {
112 case EHTokSample: idString = NewPoolTString("sample"); break;
113 case EHTokHalf: idString = NewPoolTString("half"); break;
114 case EHTokBool: idString = NewPoolTString("bool"); break;
115 case EHTokFloat: idString = NewPoolTString("float"); break;
116 case EHTokDouble: idString = NewPoolTString("double"); break;
117 case EHTokInt: idString = NewPoolTString("int"); break;
118 case EHTokUint: idString = NewPoolTString("uint"); break;
119 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
120 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
121 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
122 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
123 default:
124 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700125 }
126
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700127 token.string = idString;
128 token.tokenClass = EHTokIdentifier;
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700129 idToken = token;
130
131 advanceToken();
132
133 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600134}
135
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136// compilationUnit
John Kessenich8f9fdc92017-03-30 16:22:26 -0600137// : declaration_list EOF
John Kesseniche01a9bc2016-03-12 20:11:22 -0700138//
139bool HlslGrammar::acceptCompilationUnit()
140{
John Kessenichd016be12016-03-13 11:24:20 -0600141 TIntermNode* unitNode = nullptr;
142
John Kessenich8f9fdc92017-03-30 16:22:26 -0600143 if (! acceptDeclarationList(unitNode))
144 return false;
steve-lunargcb88de52016-08-03 07:04:18 -0600145
John Kessenich8f9fdc92017-03-30 16:22:26 -0600146 if (! peekTokenClass(EHTokNone))
147 return false;
John Kesseniche01a9bc2016-03-12 20:11:22 -0700148
John Kessenichd016be12016-03-13 11:24:20 -0600149 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700150 if (unitNode && !unitNode->getAsAggregate())
151 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600152 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600153
John Kesseniche01a9bc2016-03-12 20:11:22 -0700154 return true;
155}
156
John Kessenich8f9fdc92017-03-30 16:22:26 -0600157// Recognize the following, but with the extra condition that it can be
158// successfully terminated by EOF or '}'.
159//
160// declaration_list
161// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
162//
163// declaration_or_semicolon
164// : declaration
165// : SEMICOLON
166//
167bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
168{
169 do {
170 // HLSL allows extra semicolons between global declarations
171 do { } while (acceptTokenClass(EHTokSemicolon));
172
173 // EOF or RIGHT_BRACE
174 if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
175 return true;
176
177 // declaration
178 if (! acceptDeclaration(nodeList))
179 return false;
180 } while (true);
181
182 return true;
183}
184
LoopDawg4886f692016-06-29 10:58:58 -0600185// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700186// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600187//
188// sampler_state_assignment
189// : sampler_state_identifier EQUAL value SEMICOLON
190//
191// sampler_state_identifier
192// : ADDRESSU
193// | ADDRESSV
194// | ADDRESSW
195// | BORDERCOLOR
196// | FILTER
197// | MAXANISOTROPY
198// | MAXLOD
199// | MINLOD
200// | MIPLODBIAS
201//
202bool HlslGrammar::acceptSamplerState()
203{
204 // TODO: this should be genericized to accept a list of valid tokens and
205 // return token/value pairs. Presently it is specific to texture values.
206
207 if (! acceptTokenClass(EHTokLeftBrace))
208 return true;
209
210 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700211
LoopDawg4886f692016-06-29 10:58:58 -0600212 do {
213 // read state name
214 HlslToken state;
215 if (! acceptIdentifier(state))
216 break; // end of list
217
218 // FXC accepts any case
219 TString stateName = *state.string;
220 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
221
222 if (! acceptTokenClass(EHTokAssign)) {
223 expected("assign");
224 return false;
225 }
226
227 if (stateName == "minlod" || stateName == "maxlod") {
228 if (! peekTokenClass(EHTokIntConstant)) {
229 expected("integer");
230 return false;
231 }
232
233 TIntermTyped* lod = nullptr;
234 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
235 return false;
236 } else if (stateName == "maxanisotropy") {
237 if (! peekTokenClass(EHTokIntConstant)) {
238 expected("integer");
239 return false;
240 }
241
242 TIntermTyped* maxAnisotropy = nullptr;
243 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
244 return false;
245 } else if (stateName == "filter") {
246 HlslToken filterMode;
247 if (! acceptIdentifier(filterMode)) {
248 expected("filter mode");
249 return false;
250 }
251 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
252 HlslToken addrMode;
253 if (! acceptIdentifier(addrMode)) {
254 expected("texture address mode");
255 return false;
256 }
257 } else if (stateName == "miplodbias") {
258 TIntermTyped* lodBias = nullptr;
259 if (! acceptLiteral(lodBias)) {
260 expected("lod bias");
261 return false;
262 }
263 } else if (stateName == "bordercolor") {
264 return false;
265 } else {
266 expected("texture state");
267 return false;
268 }
269
270 // SEMICOLON
271 if (! acceptTokenClass(EHTokSemicolon)) {
272 expected("semicolon");
273 return false;
274 }
275 } while (true);
276
277 if (! acceptTokenClass(EHTokRightBrace))
278 return false;
279
280 return true;
281}
282
283// sampler_declaration_dx9
284// : SAMPLER identifier EQUAL sampler_type sampler_state
285//
John Kesseniche4821e42016-07-16 10:19:43 -0600286bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600287{
288 if (! acceptTokenClass(EHTokSampler))
289 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700290
LoopDawg4886f692016-06-29 10:58:58 -0600291 // TODO: remove this when DX9 style declarations are implemented.
292 unimplemented("Direct3D 9 sampler declaration");
293
294 // read sampler name
295 HlslToken name;
296 if (! acceptIdentifier(name)) {
297 expected("sampler name");
298 return false;
299 }
300
301 if (! acceptTokenClass(EHTokAssign)) {
302 expected("=");
303 return false;
304 }
305
306 return false;
307}
308
John Kesseniche01a9bc2016-03-12 20:11:22 -0700309// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600310// : sampler_declaration_dx9 post_decls SEMICOLON
John Kessenich13075c62017-04-11 09:51:32 -0600311// | fully_specified_type declarator_list SEMICOLON(optional for cbuffer/tbuffer)
John Kessenich630dd7d2016-06-12 23:52:12 -0600312// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600313// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600314// | typedef declaration
John Kessenich8f9fdc92017-03-30 16:22:26 -0600315// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
John Kessenich87142c72016-03-12 20:24:24 -0700316//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600317// declarator_list
318// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600319//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600320// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600321// : identifier array_specifier post_decls
322// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600323// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600324//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600325// Parsing has to go pretty far in to know whether it's a variable, prototype, or
326// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600327// as above. (The 'identifier' in the first item in init_declarator list is the
328// same as 'identifier' for function declarations.)
329//
John Kessenichca71d942017-03-07 20:44:09 -0700330// This can generate more than one subtree, one per initializer or a function body.
331// All initializer subtrees are put in their own aggregate node, making one top-level
332// node for all the initializers. Each function created is a top-level node to grow
333// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600334//
John Kessenichca71d942017-03-07 20:44:09 -0700335// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
336// each top-level node the declaration creates. Otherwise, if only one top-level
337// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700338//
John Kessenichca71d942017-03-07 20:44:09 -0700339bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700340{
John Kessenich8f9fdc92017-03-30 16:22:26 -0600341 // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
342 if (acceptTokenClass(EHTokNamespace)) {
343 HlslToken namespaceToken;
344 if (!acceptIdentifier(namespaceToken)) {
345 expected("namespace name");
346 return false;
347 }
348 parseContext.pushNamespace(*namespaceToken.string);
349 if (!acceptTokenClass(EHTokLeftBrace)) {
350 expected("{");
351 return false;
352 }
353 if (!acceptDeclarationList(nodeList)) {
354 expected("declaration list");
355 return false;
356 }
357 if (!acceptTokenClass(EHTokRightBrace)) {
358 expected("}");
359 return false;
360 }
361 parseContext.popNamespace();
362 return true;
363 }
364
John Kessenich54ee28f2017-03-11 14:13:00 -0700365 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600366
steve-lunarg1868b142016-10-20 13:07:10 -0600367 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700368 TFunctionDeclarator declarator;
369 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600370
John Kessenich5e69ec62016-07-05 00:02:40 -0600371 // typedef
372 bool typedefDecl = acceptTokenClass(EHTokTypedef);
373
John Kesseniche82061d2016-09-27 14:38:57 -0600374 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600375
376 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600377 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
378 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
379 // HLSL shaders, this will have to be a master level switch
380 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700381 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700382 // if (acceptSamplerDeclarationDX9(declaredType))
383 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600384
385 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700386 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700387 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600388
John Kessenich87142c72016-03-12 20:24:24 -0700389 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600390 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700391 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 while (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600393 const TString *fullName = idToken.string;
394 if (parseContext.symbolTable.atGlobalLevel())
395 parseContext.getFullNamespaceName(fullName);
John Kessenich78388722017-03-08 18:53:51 -0700396 if (peekTokenClass(EHTokLeftParen)) {
397 // looks like function parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600398
John Kessenich78388722017-03-08 18:53:51 -0700399 // Potentially rename shader entry point function. No-op most of the time.
John Kessenich8f9fdc92017-03-30 16:22:26 -0600400 parseContext.renameShaderFunction(fullName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600401
John Kessenich78388722017-03-08 18:53:51 -0700402 // function_parameters
John Kessenich8f9fdc92017-03-30 16:22:26 -0600403 declarator.function = new TFunction(fullName, declaredType);
John Kessenich088d52b2017-03-11 17:55:28 -0700404 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700405 expected("function parameter list");
406 return false;
407 }
408
John Kessenich630dd7d2016-06-12 23:52:12 -0600409 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700410 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600411
John Kessenichd5ed0b62016-07-04 17:32:45 -0600412 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700413 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600414 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700415 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600416 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600417 if (typedefDecl)
418 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700419 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600420 } else {
421 if (typedefDecl)
422 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700423 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600424 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600425 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600426 // A variable declaration. Fix the storage qualifier if it's a global.
427 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
428 declaredType.getQualifier().storage = EvqUniform;
429
John Kessenichecba76f2017-01-06 00:34:48 -0700430 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600431 // the number of types can expand when arrayness is different.
432 TType variableType;
433 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600434
John Kesseniche82061d2016-09-27 14:38:57 -0600435 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600436 TArraySizes* arraySizes = nullptr;
437 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600438
John Kesseniche82061d2016-09-27 14:38:57 -0600439 // Fix arrayness in the variableType
440 if (declaredType.isImplicitlySizedArray()) {
441 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
442 // of different sizes, for this case sharing the shallow copy of arrayness
443 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
444 variableType.newArraySizes(declaredType.getArraySizes());
445 }
446 if (arraySizes || variableType.isArray()) {
447 // In the most general case, arrayness is potentially coming both from the
448 // declared type and from the variable: "int[] a[];" or just one or the other.
449 // Merge it all to the variableType, so all arrayness is part of the variableType.
450 parseContext.arrayDimMerge(variableType, arraySizes);
451 }
452
LoopDawg4886f692016-06-29 10:58:58 -0600453 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600454 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600455 if (! acceptSamplerState())
456 return false;
457 }
458
John Kessenichd5ed0b62016-07-04 17:32:45 -0600459 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600460 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600461
462 // EQUAL assignment_expression
463 TIntermTyped* expressionNode = nullptr;
464 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600465 if (typedefDecl)
466 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600467 if (! acceptAssignmentExpression(expressionNode)) {
468 expected("initializer");
469 return false;
470 }
471 }
472
John Kessenich6dbc0a72016-09-27 19:13:05 -0600473 // TODO: things scoped within an annotation need their own name space;
474 // TODO: strings are not yet handled.
475 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
476 if (typedefDecl)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600477 parseContext.declareTypedef(idToken.loc, *fullName, variableType);
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 Kessenich13075c62017-04-11 09:51:32 -0600512 // SEMICOLON(optional for cbuffer/tbuffer)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600513 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich13075c62017-04-11 09:51:32 -0600514 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma) {
515 // This may have been a false detection of what appeared to be a declaration, but
516 // was actually an assignment such as "float = 4", where "float" is an identifier.
517 // We put the token back to let further parsing happen for cases where that may
518 // happen. This errors on the side of caution, and mostly triggers the error.
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700519 recedeToken();
John Kessenich13075c62017-04-11 09:51:32 -0600520 return false;
521 } else if (declaredType.getBasicType() == EbtBlock) {
522 // cbuffer, et. al. (but not struct) don't have an ending semicolon
523 return true;
524 } else {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700525 expected(";");
John Kessenich13075c62017-04-11 09:51:32 -0600526 return false;
527 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600528 }
John Kessenichecba76f2017-01-06 00:34:48 -0700529
John Kesseniche01a9bc2016-03-12 20:11:22 -0700530 return true;
531}
532
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600533// control_declaration
534// : fully_specified_type identifier EQUAL expression
535//
536bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
537{
538 node = nullptr;
539
540 // fully_specified_type
541 TType type;
542 if (! acceptFullySpecifiedType(type))
543 return false;
544
John Kessenich057df292017-03-06 18:18:37 -0700545 // filter out type casts
546 if (peekTokenClass(EHTokLeftParen)) {
547 recedeToken();
548 return false;
549 }
550
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600551 // identifier
552 HlslToken idToken;
553 if (! acceptIdentifier(idToken)) {
554 expected("identifier");
555 return false;
556 }
557
558 // EQUAL
559 TIntermTyped* expressionNode = nullptr;
560 if (! acceptTokenClass(EHTokAssign)) {
561 expected("=");
562 return false;
563 }
564
565 // expression
566 if (! acceptExpression(expressionNode)) {
567 expected("initializer");
568 return false;
569 }
570
John Kesseniche82061d2016-09-27 14:38:57 -0600571 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600572
573 return true;
574}
575
John Kessenich87142c72016-03-12 20:24:24 -0700576// fully_specified_type
577// : type_specifier
578// | type_qualifier type_specifier
579//
580bool HlslGrammar::acceptFullySpecifiedType(TType& type)
581{
John Kessenich54ee28f2017-03-11 14:13:00 -0700582 TIntermNode* nodeList = nullptr;
583 return acceptFullySpecifiedType(type, nodeList);
584}
585bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
586{
John Kessenich87142c72016-03-12 20:24:24 -0700587 // type_qualifier
588 TQualifier qualifier;
589 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600590 if (! acceptQualifier(qualifier))
591 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600592 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700593
594 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700595 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700596 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700597 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700598 // qualifier. Back it out, if we did.
599 if (qualifier.sample)
600 recedeToken();
601
John Kessenich87142c72016-03-12 20:24:24 -0700602 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700603 }
John Kessenich3d157c52016-07-25 16:05:33 -0600604 if (type.getBasicType() == EbtBlock) {
605 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600606 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600607 // further, it can create an anonymous instance of the block
John Kessenich13075c62017-04-11 09:51:32 -0600608 if (peek() != EHTokIdentifier)
John Kessenich3d157c52016-07-25 16:05:33 -0600609 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600610 } else {
611 // Some qualifiers are set when parsing the type. Merge those with
612 // whatever comes from acceptQualifier.
613 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700614
steve-lunargbb0183f2016-10-04 16:58:14 -0600615 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600616 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700617
steve-lunarg08e0c082017-03-29 20:01:13 -0600618 if (type.getQualifier().storage == EvqOut ||
steve-lunarg5da1f032017-02-12 17:50:28 -0700619 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700620 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700621 qualifier.readonly = type.getQualifier().readonly;
622 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700623
steve-lunarg08e0c082017-03-29 20:01:13 -0600624 if (type.getQualifier().builtIn != EbvNone)
625 qualifier.builtIn = type.getQualifier().builtIn;
626
steve-lunargf49cdf42016-11-17 15:04:20 -0700627 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600628 }
John Kessenich87142c72016-03-12 20:24:24 -0700629
630 return true;
631}
632
John Kessenich630dd7d2016-06-12 23:52:12 -0600633// type_qualifier
634// : qualifier qualifier ...
635//
636// Zero or more of these, so this can't return false.
637//
John Kessenichb9e39122016-08-17 10:22:08 -0600638bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700639{
John Kessenich630dd7d2016-06-12 23:52:12 -0600640 do {
641 switch (peek()) {
642 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600643 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600644 break;
645 case EHTokExtern:
646 // TODO: no meaning in glslang?
647 break;
648 case EHTokShared:
649 // TODO: hint
650 break;
651 case EHTokGroupShared:
652 qualifier.storage = EvqShared;
653 break;
654 case EHTokUniform:
655 qualifier.storage = EvqUniform;
656 break;
657 case EHTokConst:
658 qualifier.storage = EvqConst;
659 break;
660 case EHTokVolatile:
661 qualifier.volatil = true;
662 break;
663 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600664 qualifier.smooth = true;
665 break;
666 case EHTokCentroid:
667 qualifier.centroid = true;
668 break;
669 case EHTokNointerpolation:
670 qualifier.flat = true;
671 break;
672 case EHTokNoperspective:
673 qualifier.nopersp = true;
674 break;
675 case EHTokSample:
676 qualifier.sample = true;
677 break;
678 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600679 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600680 break;
681 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600682 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600683 break;
684 case EHTokPrecise:
685 qualifier.noContraction = true;
686 break;
LoopDawg9249c702016-07-12 20:44:32 -0600687 case EHTokIn:
688 qualifier.storage = EvqIn;
689 break;
690 case EHTokOut:
691 qualifier.storage = EvqOut;
692 break;
693 case EHTokInOut:
694 qualifier.storage = EvqInOut;
695 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600696 case EHTokLayout:
697 if (! acceptLayoutQualifierList(qualifier))
698 return false;
699 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700700 case EHTokGloballyCoherent:
701 qualifier.coherent = true;
702 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600703 case EHTokInline:
704 // TODO: map this to SPIR-V function control
705 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700706
707 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
708 // for output variables.
709 case EHTokPoint:
710 qualifier.storage = EvqIn;
711 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
712 return false;
713 break;
714 case EHTokLine:
715 qualifier.storage = EvqIn;
716 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
717 return false;
718 break;
719 case EHTokTriangle:
720 qualifier.storage = EvqIn;
721 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
722 return false;
723 break;
724 case EHTokLineAdj:
725 qualifier.storage = EvqIn;
726 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
727 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700728 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700729 case EHTokTriangleAdj:
730 qualifier.storage = EvqIn;
731 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
732 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700733 break;
734
John Kessenich630dd7d2016-06-12 23:52:12 -0600735 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600736 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600737 }
738 advanceToken();
739 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700740}
741
John Kessenichb9e39122016-08-17 10:22:08 -0600742// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600743// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600744//
745// layout_qualifier
746// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600747// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600748//
749// Zero or more of these, so this can't return false.
750//
751bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
752{
753 if (! acceptTokenClass(EHTokLayout))
754 return false;
755
756 // LEFT_PAREN
757 if (! acceptTokenClass(EHTokLeftParen))
758 return false;
759
760 do {
761 // identifier
762 HlslToken idToken;
763 if (! acceptIdentifier(idToken))
764 break;
765
766 // EQUAL expression
767 if (acceptTokenClass(EHTokAssign)) {
768 TIntermTyped* expr;
769 if (! acceptConditionalExpression(expr)) {
770 expected("expression");
771 return false;
772 }
773 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
774 } else
775 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
776
777 // COMMA
778 if (! acceptTokenClass(EHTokComma))
779 break;
780 } while (true);
781
782 // RIGHT_PAREN
783 if (! acceptTokenClass(EHTokRightParen)) {
784 expected(")");
785 return false;
786 }
787
788 return true;
789}
790
LoopDawg6daaa4f2016-06-23 19:13:48 -0600791// template_type
792// : FLOAT
793// | DOUBLE
794// | INT
795// | DWORD
796// | UINT
797// | BOOL
798//
steve-lunargf49cdf42016-11-17 15:04:20 -0700799bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600800{
801 switch (peek()) {
802 case EHTokFloat:
803 basicType = EbtFloat;
804 break;
805 case EHTokDouble:
806 basicType = EbtDouble;
807 break;
808 case EHTokInt:
809 case EHTokDword:
810 basicType = EbtInt;
811 break;
812 case EHTokUint:
813 basicType = EbtUint;
814 break;
815 case EHTokBool:
816 basicType = EbtBool;
817 break;
818 default:
819 return false;
820 }
821
822 advanceToken();
823
824 return true;
825}
826
827// vector_template_type
828// : VECTOR
829// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
830//
831bool HlslGrammar::acceptVectorTemplateType(TType& type)
832{
833 if (! acceptTokenClass(EHTokVector))
834 return false;
835
836 if (! acceptTokenClass(EHTokLeftAngle)) {
837 // in HLSL, 'vector' alone means float4.
838 new(&type) TType(EbtFloat, EvqTemporary, 4);
839 return true;
840 }
841
842 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700843 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600844 expected("scalar type");
845 return false;
846 }
847
848 // COMMA
849 if (! acceptTokenClass(EHTokComma)) {
850 expected(",");
851 return false;
852 }
853
854 // integer
855 if (! peekTokenClass(EHTokIntConstant)) {
856 expected("literal integer");
857 return false;
858 }
859
860 TIntermTyped* vecSize;
861 if (! acceptLiteral(vecSize))
862 return false;
863
864 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
865
866 new(&type) TType(basicType, EvqTemporary, vecSizeI);
867
868 if (vecSizeI == 1)
869 type.makeVector();
870
871 if (!acceptTokenClass(EHTokRightAngle)) {
872 expected("right angle bracket");
873 return false;
874 }
875
876 return true;
877}
878
879// matrix_template_type
880// : MATRIX
881// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
882//
883bool HlslGrammar::acceptMatrixTemplateType(TType& type)
884{
885 if (! acceptTokenClass(EHTokMatrix))
886 return false;
887
888 if (! acceptTokenClass(EHTokLeftAngle)) {
889 // in HLSL, 'matrix' alone means float4x4.
890 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
891 return true;
892 }
893
894 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700895 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600896 expected("scalar type");
897 return false;
898 }
899
900 // COMMA
901 if (! acceptTokenClass(EHTokComma)) {
902 expected(",");
903 return false;
904 }
905
906 // integer rows
907 if (! peekTokenClass(EHTokIntConstant)) {
908 expected("literal integer");
909 return false;
910 }
911
912 TIntermTyped* rows;
913 if (! acceptLiteral(rows))
914 return false;
915
916 // COMMA
917 if (! acceptTokenClass(EHTokComma)) {
918 expected(",");
919 return false;
920 }
John Kessenichecba76f2017-01-06 00:34:48 -0700921
LoopDawg6daaa4f2016-06-23 19:13:48 -0600922 // integer cols
923 if (! peekTokenClass(EHTokIntConstant)) {
924 expected("literal integer");
925 return false;
926 }
927
928 TIntermTyped* cols;
929 if (! acceptLiteral(cols))
930 return false;
931
932 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600933 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
934 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600935
936 if (!acceptTokenClass(EHTokRightAngle)) {
937 expected("right angle bracket");
938 return false;
939 }
940
941 return true;
942}
943
steve-lunargf49cdf42016-11-17 15:04:20 -0700944// layout_geometry
945// : LINESTREAM
946// | POINTSTREAM
947// | TRIANGLESTREAM
948//
949bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
950{
951 // read geometry type
952 const EHlslTokenClass geometryType = peek();
953
954 switch (geometryType) {
955 case EHTokPointStream: geometry = ElgPoints; break;
956 case EHTokLineStream: geometry = ElgLineStrip; break;
957 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
958 default:
959 return false; // not a layout geometry
960 }
961
962 advanceToken(); // consume the layout keyword
963 return true;
964}
965
steve-lunarg858c9282017-01-07 08:54:10 -0700966// tessellation_decl_type
967// : INPUTPATCH
968// | OUTPUTPATCH
969//
steve-lunarg067eb9b2017-04-01 15:34:48 -0600970bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
steve-lunarg858c9282017-01-07 08:54:10 -0700971{
972 // read geometry type
973 const EHlslTokenClass tessType = peek();
974
975 switch (tessType) {
steve-lunarg067eb9b2017-04-01 15:34:48 -0600976 case EHTokInputPatch: patchType = EbvInputPatch; break;
977 case EHTokOutputPatch: patchType = EbvOutputPatch; break;
steve-lunarg858c9282017-01-07 08:54:10 -0700978 default:
979 return false; // not a tessellation decl
980 }
981
982 advanceToken(); // consume the keyword
983 return true;
984}
985
986// tessellation_patch_template_type
987// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
988//
989bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
990{
steve-lunarg067eb9b2017-04-01 15:34:48 -0600991 TBuiltInVariable patchType;
992
993 if (! acceptTessellationDeclType(patchType))
steve-lunarg858c9282017-01-07 08:54:10 -0700994 return false;
995
996 if (! acceptTokenClass(EHTokLeftAngle))
997 return false;
998
999 if (! acceptType(type)) {
1000 expected("tessellation patch type");
1001 return false;
1002 }
1003
1004 if (! acceptTokenClass(EHTokComma))
1005 return false;
1006
1007 // integer size
1008 if (! peekTokenClass(EHTokIntConstant)) {
1009 expected("literal integer");
1010 return false;
1011 }
1012
1013 TIntermTyped* size;
1014 if (! acceptLiteral(size))
1015 return false;
1016
1017 TArraySizes* arraySizes = new TArraySizes;
1018 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1019 type.newArraySizes(*arraySizes);
steve-lunarg067eb9b2017-04-01 15:34:48 -06001020 type.getQualifier().builtIn = patchType;
steve-lunarg858c9282017-01-07 08:54:10 -07001021
1022 if (! acceptTokenClass(EHTokRightAngle)) {
1023 expected("right angle bracket");
1024 return false;
1025 }
1026
1027 return true;
1028}
1029
steve-lunargf49cdf42016-11-17 15:04:20 -07001030// stream_out_template_type
1031// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1032//
1033bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1034{
1035 geometry = ElgNone;
1036
1037 if (! acceptOutputPrimitiveGeometry(geometry))
1038 return false;
1039
1040 if (! acceptTokenClass(EHTokLeftAngle))
1041 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001042
steve-lunargf49cdf42016-11-17 15:04:20 -07001043 if (! acceptType(type)) {
1044 expected("stream output type");
1045 return false;
1046 }
1047
steve-lunarg08e0c082017-03-29 20:01:13 -06001048 type.getQualifier().storage = EvqOut;
1049 type.getQualifier().builtIn = EbvGsOutputStream;
steve-lunargf49cdf42016-11-17 15:04:20 -07001050
1051 if (! acceptTokenClass(EHTokRightAngle)) {
1052 expected("right angle bracket");
1053 return false;
1054 }
1055
1056 return true;
1057}
John Kessenichecba76f2017-01-06 00:34:48 -07001058
John Kessenicha1e2d492016-09-20 13:22:58 -06001059// annotations
1060// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001061//
John Kessenicha1e2d492016-09-20 13:22:58 -06001062bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001063{
John Kessenicha1e2d492016-09-20 13:22:58 -06001064 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001065 return false;
1066
John Kessenicha1e2d492016-09-20 13:22:58 -06001067 // note that we are nesting a name space
1068 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001069
1070 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1071 do {
1072 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1073 while (acceptTokenClass(EHTokSemicolon))
1074 ;
1075
1076 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001077 break;
John Kessenich86f71382016-09-19 20:23:18 -06001078
1079 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001080 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001081 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001082 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001083 return false;
1084 }
1085 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001086
1087 parseContext.unnestAnnotations();
1088 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001089}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001090
LoopDawg4886f692016-06-29 10:58:58 -06001091// sampler_type
1092// : SAMPLER
1093// | SAMPLER1D
1094// | SAMPLER2D
1095// | SAMPLER3D
1096// | SAMPLERCUBE
1097// | SAMPLERSTATE
1098// | SAMPLERCOMPARISONSTATE
1099bool HlslGrammar::acceptSamplerType(TType& type)
1100{
1101 // read sampler type
1102 const EHlslTokenClass samplerType = peek();
1103
LoopDawga78b0292016-07-19 14:28:05 -06001104 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001105 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001106
LoopDawga78b0292016-07-19 14:28:05 -06001107 bool isShadow = false;
1108
LoopDawg4886f692016-06-29 10:58:58 -06001109 switch (samplerType) {
1110 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001111 case EHTokSampler1d: /*dim = Esd1D*/; break;
1112 case EHTokSampler2d: /*dim = Esd2D*/; break;
1113 case EHTokSampler3d: /*dim = Esd3D*/; break;
1114 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001115 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001116 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001117 default:
1118 return false; // not a sampler declaration
1119 }
1120
1121 advanceToken(); // consume the sampler type keyword
1122
1123 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001124
1125 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001126 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001127
1128 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1129
1130 return true;
1131}
1132
1133// texture_type
1134// | BUFFER
1135// | TEXTURE1D
1136// | TEXTURE1DARRAY
1137// | TEXTURE2D
1138// | TEXTURE2DARRAY
1139// | TEXTURE3D
1140// | TEXTURECUBE
1141// | TEXTURECUBEARRAY
1142// | TEXTURE2DMS
1143// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001144// | RWBUFFER
1145// | RWTEXTURE1D
1146// | RWTEXTURE1DARRAY
1147// | RWTEXTURE2D
1148// | RWTEXTURE2DARRAY
1149// | RWTEXTURE3D
1150
LoopDawg4886f692016-06-29 10:58:58 -06001151bool HlslGrammar::acceptTextureType(TType& type)
1152{
1153 const EHlslTokenClass textureType = peek();
1154
1155 TSamplerDim dim = EsdNone;
1156 bool array = false;
1157 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001158 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001159 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001160
1161 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001162 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001163 case EHTokTexture1d: dim = Esd1D; break;
1164 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1165 case EHTokTexture2d: dim = Esd2D; break;
1166 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1167 case EHTokTexture3d: dim = Esd3D; break;
1168 case EHTokTextureCube: dim = EsdCube; break;
1169 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1170 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1171 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1172 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1173 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1174 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1175 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1176 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1177 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001178 default:
1179 return false; // not a texture declaration
1180 }
1181
1182 advanceToken(); // consume the texture object keyword
1183
1184 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001185
LoopDawg4886f692016-06-29 10:58:58 -06001186 TIntermTyped* msCount = nullptr;
1187
steve-lunargbb0183f2016-10-04 16:58:14 -06001188 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001189 if (acceptTokenClass(EHTokLeftAngle)) {
1190 if (! acceptType(txType)) {
1191 expected("scalar or vector type");
1192 return false;
1193 }
1194
1195 const TBasicType basicRetType = txType.getBasicType() ;
1196
1197 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1198 unimplemented("basic type in texture");
1199 return false;
1200 }
1201
steve-lunargd53f7172016-07-27 15:46:48 -06001202 // Buffers can handle small mats if they fit in 4 components
1203 if (dim == EsdBuffer && txType.isMatrix()) {
1204 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1205 expected("components < 4 in matrix buffer type");
1206 return false;
1207 }
1208
1209 // TODO: except we don't handle it yet...
1210 unimplemented("matrix type in buffer");
1211 return false;
1212 }
1213
LoopDawg4886f692016-06-29 10:58:58 -06001214 if (!txType.isScalar() && !txType.isVector()) {
1215 expected("scalar or vector type");
1216 return false;
1217 }
1218
LoopDawg4886f692016-06-29 10:58:58 -06001219 if (ms && acceptTokenClass(EHTokComma)) {
1220 // read sample count for multisample types, if given
1221 if (! peekTokenClass(EHTokIntConstant)) {
1222 expected("multisample count");
1223 return false;
1224 }
1225
1226 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1227 return false;
1228 }
1229
1230 if (! acceptTokenClass(EHTokRightAngle)) {
1231 expected("right angle bracket");
1232 return false;
1233 }
1234 } else if (ms) {
1235 expected("texture type for multisample");
1236 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001237 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001238 expected("type for RWTexture/RWBuffer");
1239 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001240 }
1241
1242 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001243 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001244
1245 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001246 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001247
steve-lunarg4f2da272016-10-10 15:24:57 -06001248 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1249 if (image || dim == EsdBuffer)
1250 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001251
1252 // Non-image Buffers are combined
1253 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001254 sampler.set(txType.getBasicType(), dim, array);
1255 } else {
1256 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001257 if (image) {
1258 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1259 } else {
1260 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1261 }
steve-lunargd53f7172016-07-27 15:46:48 -06001262 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001263
1264 // Remember the declared vector size.
1265 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001266
steve-lunargbf1537f2017-03-31 17:40:09 -06001267 // Force uncombined, if necessary
1268 if (!combined)
1269 sampler.combined = false;
1270
LoopDawg4886f692016-06-29 10:58:58 -06001271 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001272 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001273
1274 return true;
1275}
1276
John Kessenich87142c72016-03-12 20:24:24 -07001277// If token is for a type, update 'type' with the type information,
1278// and return true and advance.
1279// Otherwise, return false, and don't advance
1280bool HlslGrammar::acceptType(TType& type)
1281{
John Kessenich54ee28f2017-03-11 14:13:00 -07001282 TIntermNode* nodeList = nullptr;
1283 return acceptType(type, nodeList);
1284}
1285bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1286{
steve-lunarg3226b082016-10-26 19:18:55 -06001287 // Basic types for min* types, broken out here in case of future
1288 // changes, e.g, to use native halfs.
1289 static const TBasicType min16float_bt = EbtFloat;
1290 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001291 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001292 static const TBasicType min16int_bt = EbtInt;
1293 static const TBasicType min12int_bt = EbtInt;
1294 static const TBasicType min16uint_bt = EbtUint;
1295
John Kessenich9c86c6a2016-05-03 22:49:24 -06001296 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001297 case EHTokVector:
1298 return acceptVectorTemplateType(type);
1299 break;
1300
1301 case EHTokMatrix:
1302 return acceptMatrixTemplateType(type);
1303 break;
1304
steve-lunargf49cdf42016-11-17 15:04:20 -07001305 case EHTokPointStream: // fall through
1306 case EHTokLineStream: // ...
1307 case EHTokTriangleStream: // ...
1308 {
1309 TLayoutGeometry geometry;
1310 if (! acceptStreamOutTemplateType(type, geometry))
1311 return false;
1312
1313 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1314 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001315
steve-lunargf49cdf42016-11-17 15:04:20 -07001316 return true;
1317 }
1318
steve-lunarg858c9282017-01-07 08:54:10 -07001319 case EHTokInputPatch: // fall through
1320 case EHTokOutputPatch: // ...
1321 {
1322 if (! acceptTessellationPatchTemplateType(type))
1323 return false;
1324
1325 return true;
1326 }
1327
LoopDawg4886f692016-06-29 10:58:58 -06001328 case EHTokSampler: // fall through
1329 case EHTokSampler1d: // ...
1330 case EHTokSampler2d: // ...
1331 case EHTokSampler3d: // ...
1332 case EHTokSamplerCube: // ...
1333 case EHTokSamplerState: // ...
1334 case EHTokSamplerComparisonState: // ...
1335 return acceptSamplerType(type);
1336 break;
1337
1338 case EHTokBuffer: // fall through
1339 case EHTokTexture1d: // ...
1340 case EHTokTexture1darray: // ...
1341 case EHTokTexture2d: // ...
1342 case EHTokTexture2darray: // ...
1343 case EHTokTexture3d: // ...
1344 case EHTokTextureCube: // ...
1345 case EHTokTextureCubearray: // ...
1346 case EHTokTexture2DMS: // ...
1347 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001348 case EHTokRWTexture1d: // ...
1349 case EHTokRWTexture1darray: // ...
1350 case EHTokRWTexture2d: // ...
1351 case EHTokRWTexture2darray: // ...
1352 case EHTokRWTexture3d: // ...
1353 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001354 return acceptTextureType(type);
1355 break;
1356
steve-lunarg5da1f032017-02-12 17:50:28 -07001357 case EHTokAppendStructuredBuffer:
1358 case EHTokByteAddressBuffer:
1359 case EHTokConsumeStructuredBuffer:
1360 case EHTokRWByteAddressBuffer:
1361 case EHTokRWStructuredBuffer:
1362 case EHTokStructuredBuffer:
1363 return acceptStructBufferType(type);
1364 break;
1365
John Kessenich27ffb292017-03-03 17:01:01 -07001366 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001367 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001368 case EHTokCBuffer:
1369 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001370 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001371
1372 case EHTokIdentifier:
1373 // An identifier could be for a user-defined type.
1374 // Note we cache the symbol table lookup, to save for a later rule
1375 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001376 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001377 advanceToken();
1378 return true;
1379 } else
1380 return false;
1381
John Kessenich71351de2016-06-08 12:50:56 -06001382 case EHTokVoid:
1383 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001384 break;
John Kessenich71351de2016-06-08 12:50:56 -06001385
John Kessenicha1e2d492016-09-20 13:22:58 -06001386 case EHTokString:
1387 new(&type) TType(EbtString);
1388 break;
1389
John Kessenich87142c72016-03-12 20:24:24 -07001390 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001391 new(&type) TType(EbtFloat);
1392 break;
John Kessenich87142c72016-03-12 20:24:24 -07001393 case EHTokFloat1:
1394 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001395 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001396 break;
John Kessenich87142c72016-03-12 20:24:24 -07001397 case EHTokFloat2:
1398 new(&type) TType(EbtFloat, EvqTemporary, 2);
1399 break;
1400 case EHTokFloat3:
1401 new(&type) TType(EbtFloat, EvqTemporary, 3);
1402 break;
1403 case EHTokFloat4:
1404 new(&type) TType(EbtFloat, EvqTemporary, 4);
1405 break;
1406
John Kessenich71351de2016-06-08 12:50:56 -06001407 case EHTokDouble:
1408 new(&type) TType(EbtDouble);
1409 break;
1410 case EHTokDouble1:
1411 new(&type) TType(EbtDouble);
1412 type.makeVector();
1413 break;
1414 case EHTokDouble2:
1415 new(&type) TType(EbtDouble, EvqTemporary, 2);
1416 break;
1417 case EHTokDouble3:
1418 new(&type) TType(EbtDouble, EvqTemporary, 3);
1419 break;
1420 case EHTokDouble4:
1421 new(&type) TType(EbtDouble, EvqTemporary, 4);
1422 break;
1423
1424 case EHTokInt:
1425 case EHTokDword:
1426 new(&type) TType(EbtInt);
1427 break;
1428 case EHTokInt1:
1429 new(&type) TType(EbtInt);
1430 type.makeVector();
1431 break;
John Kessenich87142c72016-03-12 20:24:24 -07001432 case EHTokInt2:
1433 new(&type) TType(EbtInt, EvqTemporary, 2);
1434 break;
1435 case EHTokInt3:
1436 new(&type) TType(EbtInt, EvqTemporary, 3);
1437 break;
1438 case EHTokInt4:
1439 new(&type) TType(EbtInt, EvqTemporary, 4);
1440 break;
1441
John Kessenich71351de2016-06-08 12:50:56 -06001442 case EHTokUint:
1443 new(&type) TType(EbtUint);
1444 break;
1445 case EHTokUint1:
1446 new(&type) TType(EbtUint);
1447 type.makeVector();
1448 break;
1449 case EHTokUint2:
1450 new(&type) TType(EbtUint, EvqTemporary, 2);
1451 break;
1452 case EHTokUint3:
1453 new(&type) TType(EbtUint, EvqTemporary, 3);
1454 break;
1455 case EHTokUint4:
1456 new(&type) TType(EbtUint, EvqTemporary, 4);
1457 break;
1458
1459 case EHTokBool:
1460 new(&type) TType(EbtBool);
1461 break;
1462 case EHTokBool1:
1463 new(&type) TType(EbtBool);
1464 type.makeVector();
1465 break;
John Kessenich87142c72016-03-12 20:24:24 -07001466 case EHTokBool2:
1467 new(&type) TType(EbtBool, EvqTemporary, 2);
1468 break;
1469 case EHTokBool3:
1470 new(&type) TType(EbtBool, EvqTemporary, 3);
1471 break;
1472 case EHTokBool4:
1473 new(&type) TType(EbtBool, EvqTemporary, 4);
1474 break;
1475
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001476 case EHTokHalf:
1477 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1478 break;
1479 case EHTokHalf1:
1480 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1481 type.makeVector();
1482 break;
1483 case EHTokHalf2:
1484 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1485 break;
1486 case EHTokHalf3:
1487 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1488 break;
1489 case EHTokHalf4:
1490 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1491 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001492
steve-lunarg3226b082016-10-26 19:18:55 -06001493 case EHTokMin16float:
1494 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1495 break;
1496 case EHTokMin16float1:
1497 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1498 type.makeVector();
1499 break;
1500 case EHTokMin16float2:
1501 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1502 break;
1503 case EHTokMin16float3:
1504 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1505 break;
1506 case EHTokMin16float4:
1507 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1508 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001509
steve-lunarg3226b082016-10-26 19:18:55 -06001510 case EHTokMin10float:
1511 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1512 break;
1513 case EHTokMin10float1:
1514 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1515 type.makeVector();
1516 break;
1517 case EHTokMin10float2:
1518 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1519 break;
1520 case EHTokMin10float3:
1521 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1522 break;
1523 case EHTokMin10float4:
1524 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1525 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001526
steve-lunarg3226b082016-10-26 19:18:55 -06001527 case EHTokMin16int:
1528 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1529 break;
1530 case EHTokMin16int1:
1531 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1532 type.makeVector();
1533 break;
1534 case EHTokMin16int2:
1535 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1536 break;
1537 case EHTokMin16int3:
1538 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1539 break;
1540 case EHTokMin16int4:
1541 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1542 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001543
steve-lunarg3226b082016-10-26 19:18:55 -06001544 case EHTokMin12int:
1545 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1546 break;
1547 case EHTokMin12int1:
1548 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1549 type.makeVector();
1550 break;
1551 case EHTokMin12int2:
1552 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1553 break;
1554 case EHTokMin12int3:
1555 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1556 break;
1557 case EHTokMin12int4:
1558 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1559 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001560
steve-lunarg3226b082016-10-26 19:18:55 -06001561 case EHTokMin16uint:
1562 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1563 break;
1564 case EHTokMin16uint1:
1565 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1566 type.makeVector();
1567 break;
1568 case EHTokMin16uint2:
1569 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1570 break;
1571 case EHTokMin16uint3:
1572 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1573 break;
1574 case EHTokMin16uint4:
1575 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1576 break;
1577
John Kessenich0133c122016-05-20 12:17:26 -06001578 case EHTokInt1x1:
1579 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1580 break;
1581 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001582 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001583 break;
1584 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001585 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001586 break;
1587 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001588 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001589 break;
1590 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001591 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001592 break;
1593 case EHTokInt2x2:
1594 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1595 break;
1596 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001597 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001598 break;
1599 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001600 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001601 break;
1602 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001603 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001604 break;
1605 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001606 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001607 break;
1608 case EHTokInt3x3:
1609 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1610 break;
1611 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001612 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001613 break;
1614 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001615 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001616 break;
1617 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001618 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001619 break;
1620 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001621 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001622 break;
1623 case EHTokInt4x4:
1624 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1625 break;
1626
John Kessenich71351de2016-06-08 12:50:56 -06001627 case EHTokUint1x1:
1628 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1629 break;
1630 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001631 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001632 break;
1633 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001634 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001635 break;
1636 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001637 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001638 break;
1639 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001640 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001641 break;
1642 case EHTokUint2x2:
1643 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1644 break;
1645 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001646 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001647 break;
1648 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001649 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001650 break;
1651 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001652 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001653 break;
1654 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001655 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001656 break;
1657 case EHTokUint3x3:
1658 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1659 break;
1660 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001661 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001662 break;
1663 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001664 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001665 break;
1666 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001667 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001668 break;
1669 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001670 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001671 break;
1672 case EHTokUint4x4:
1673 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1674 break;
1675
1676 case EHTokBool1x1:
1677 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1678 break;
1679 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001680 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001681 break;
1682 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001683 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001684 break;
1685 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001686 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001687 break;
1688 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001689 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001690 break;
1691 case EHTokBool2x2:
1692 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1693 break;
1694 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001695 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001696 break;
1697 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001698 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001699 break;
1700 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001701 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001702 break;
1703 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001704 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001705 break;
1706 case EHTokBool3x3:
1707 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1708 break;
1709 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001710 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001711 break;
1712 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001713 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001714 break;
1715 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001716 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001717 break;
1718 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001719 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001720 break;
1721 case EHTokBool4x4:
1722 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1723 break;
1724
John Kessenich0133c122016-05-20 12:17:26 -06001725 case EHTokFloat1x1:
1726 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1727 break;
1728 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001729 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001730 break;
1731 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001732 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001733 break;
1734 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001735 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001736 break;
1737 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001738 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001739 break;
John Kessenich87142c72016-03-12 20:24:24 -07001740 case EHTokFloat2x2:
1741 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1742 break;
1743 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001744 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001745 break;
1746 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001747 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001748 break;
John Kessenich0133c122016-05-20 12:17:26 -06001749 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001750 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001751 break;
John Kessenich87142c72016-03-12 20:24:24 -07001752 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001753 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001754 break;
1755 case EHTokFloat3x3:
1756 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1757 break;
1758 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001759 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001760 break;
John Kessenich0133c122016-05-20 12:17:26 -06001761 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001762 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001763 break;
John Kessenich87142c72016-03-12 20:24:24 -07001764 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001765 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001766 break;
1767 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001768 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001769 break;
1770 case EHTokFloat4x4:
1771 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1772 break;
1773
John Kessenich0133c122016-05-20 12:17:26 -06001774 case EHTokDouble1x1:
1775 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1776 break;
1777 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001778 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001779 break;
1780 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001781 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001782 break;
1783 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001784 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001785 break;
1786 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001787 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001788 break;
1789 case EHTokDouble2x2:
1790 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1791 break;
1792 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001793 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001794 break;
1795 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001796 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001797 break;
1798 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001799 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001800 break;
1801 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001802 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001803 break;
1804 case EHTokDouble3x3:
1805 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1806 break;
1807 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001808 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001809 break;
1810 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001811 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001812 break;
1813 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001814 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001815 break;
1816 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001817 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001818 break;
1819 case EHTokDouble4x4:
1820 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1821 break;
1822
John Kessenich87142c72016-03-12 20:24:24 -07001823 default:
1824 return false;
1825 }
1826
1827 advanceToken();
1828
1829 return true;
1830}
1831
John Kesseniche6e74942016-06-11 16:43:14 -06001832// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001833// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1834// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001835// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001836//
1837// struct_type
1838// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001839// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001840// | CBUFFER
1841// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001842//
John Kessenich54ee28f2017-03-11 14:13:00 -07001843bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001844{
John Kessenichb804de62016-09-05 12:19:18 -06001845 // This storage qualifier will tell us whether it's an AST
1846 // block type or just a generic structure type.
1847 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001848
1849 // CBUFFER
1850 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001851 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001852 // TBUFFER
1853 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001854 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001855 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001856 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001857 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001858 return false;
1859
1860 // IDENTIFIER
1861 TString structName = "";
1862 if (peekTokenClass(EHTokIdentifier)) {
1863 structName = *token.string;
1864 advanceToken();
1865 }
1866
John Kessenich3d157c52016-07-25 16:05:33 -06001867 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001868 TQualifier postDeclQualifier;
1869 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001870 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001871
John Kessenichf3d88bd2017-03-19 12:24:29 -06001872 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001873 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001874 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001875 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1876 // struct_type IDENTIFIER
1877 return true;
1878 } else {
1879 expected("{");
1880 return false;
1881 }
John Kesseniche6e74942016-06-11 16:43:14 -06001882 }
1883
John Kessenichf3d88bd2017-03-19 12:24:29 -06001884
John Kesseniche6e74942016-06-11 16:43:14 -06001885 // struct_declaration_list
1886 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001887 // Save each member function so they can be processed after we have a fully formed 'this'.
1888 TVector<TFunctionDeclarator> functionDeclarators;
1889
1890 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001891 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001892 parseContext.popNamespace();
1893
1894 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001895 expected("struct member declarations");
1896 return false;
1897 }
1898
1899 // RIGHT_BRACE
1900 if (! acceptTokenClass(EHTokRightBrace)) {
1901 expected("}");
1902 return false;
1903 }
1904
1905 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001906 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001907 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001908 else {
John Kessenich7735b942016-09-05 12:40:06 -06001909 postDeclQualifier.storage = storageQualifier;
1910 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001911 }
John Kesseniche6e74942016-06-11 16:43:14 -06001912
John Kessenich727b3742017-02-03 17:57:55 -07001913 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001914
John Kessenich4960baa2017-03-19 18:09:59 -06001915 // For member functions: now that we know the type of 'this', go back and
1916 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1917 // - parse the functions, their tokens were saved for deferred parsing (now)
1918 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1919 // update signature
1920 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001921 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001922 }
1923
John Kessenichf3d88bd2017-03-19 12:24:29 -06001924 // All member functions get parsed inside the class/struct namespace and with the
1925 // class/struct members in a symbol-table level.
1926 parseContext.pushNamespace(structName);
John Kessenich37789792017-03-21 23:56:40 -06001927 parseContext.pushThisScope(type);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001928 bool deferredSuccess = true;
1929 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1930 // parse body
1931 pushTokenStream(functionDeclarators[b].body);
1932 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1933 deferredSuccess = false;
1934 popTokenStream();
1935 }
John Kessenich37789792017-03-21 23:56:40 -06001936 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001937 parseContext.popNamespace();
1938
1939 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001940}
1941
steve-lunarg5da1f032017-02-12 17:50:28 -07001942// struct_buffer
1943// : APPENDSTRUCTUREDBUFFER
1944// | BYTEADDRESSBUFFER
1945// | CONSUMESTRUCTUREDBUFFER
1946// | RWBYTEADDRESSBUFFER
1947// | RWSTRUCTUREDBUFFER
1948// | STRUCTUREDBUFFER
1949bool HlslGrammar::acceptStructBufferType(TType& type)
1950{
1951 const EHlslTokenClass structBuffType = peek();
1952
1953 // TODO: globallycoherent
1954 bool hasTemplateType = true;
1955 bool readonly = false;
1956
1957 TStorageQualifier storage = EvqBuffer;
1958
1959 switch (structBuffType) {
1960 case EHTokAppendStructuredBuffer:
1961 unimplemented("AppendStructuredBuffer");
1962 return false;
1963 case EHTokByteAddressBuffer:
1964 hasTemplateType = false;
1965 readonly = true;
1966 break;
1967 case EHTokConsumeStructuredBuffer:
1968 unimplemented("ConsumeStructuredBuffer");
1969 return false;
1970 case EHTokRWByteAddressBuffer:
1971 hasTemplateType = false;
1972 break;
1973 case EHTokRWStructuredBuffer:
1974 break;
1975 case EHTokStructuredBuffer:
1976 readonly = true;
1977 break;
1978 default:
1979 return false; // not a structure buffer type
1980 }
1981
1982 advanceToken(); // consume the structure keyword
1983
1984 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1985 TType* templateType = new TType;
1986
1987 if (hasTemplateType) {
1988 if (! acceptTokenClass(EHTokLeftAngle)) {
1989 expected("left angle bracket");
1990 return false;
1991 }
1992
1993 if (! acceptType(*templateType)) {
1994 expected("type");
1995 return false;
1996 }
1997 if (! acceptTokenClass(EHTokRightAngle)) {
1998 expected("right angle bracket");
1999 return false;
2000 }
2001 } else {
2002 // byte address buffers have no explicit type.
2003 TType uintType(EbtUint, storage);
2004 templateType->shallowCopy(uintType);
2005 }
2006
2007 // Create an unsized array out of that type.
2008 // TODO: does this work if it's already an array type?
2009 TArraySizes unsizedArray;
2010 unsizedArray.addInnerSize(UnsizedArraySize);
2011 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002012 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002013
2014 // field name is canonical for all structbuffers
2015 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002016
2017 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07002018
steve-lunarg5da1f032017-02-12 17:50:28 -07002019 TTypeList* blockStruct = new TTypeList;
2020 TTypeLoc member = { templateType, token.loc };
2021 blockStruct->push_back(member);
2022
steve-lunargdd8287a2017-02-23 18:04:12 -07002023 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002024 TType blockType(blockStruct, "", templateType->getQualifier());
2025
steve-lunargdd8287a2017-02-23 18:04:12 -07002026 blockType.getQualifier().storage = storage;
2027 blockType.getQualifier().readonly = readonly;
2028
2029 // We may have created an equivalent type before, in which case we should use its
2030 // deep structure.
2031 parseContext.shareStructBufferType(blockType);
2032
steve-lunarg5da1f032017-02-12 17:50:28 -07002033 type.shallowCopy(blockType);
2034
2035 return true;
2036}
2037
John Kesseniche6e74942016-06-11 16:43:14 -06002038// struct_declaration_list
2039// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2040//
2041// struct_declaration
2042// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002043// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002044//
2045// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002046// : IDENTIFIER post_decls
2047// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002048// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002049//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002050bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002051 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002052{
2053 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002054 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002055
2056 do {
2057 // success on seeing the RIGHT_BRACE coming up
2058 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002059 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002060
2061 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002062
2063 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002064
2065 // fully_specified_type
2066 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002067 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002068 expected("member type");
2069 return false;
2070 }
2071
2072 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002073 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002074 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002075 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002076 expected("member name");
2077 return false;
2078 }
2079
John Kessenich54ee28f2017-03-11 14:13:00 -07002080 if (peekTokenClass(EHTokLeftParen)) {
2081 // function_parameters
2082 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002083 declarators.resize(declarators.size() + 1);
2084 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002085 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2086 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002087 if (functionDefinitionAccepted)
2088 break;
2089 }
2090 expected("member-function definition");
2091 return false;
2092 } else {
2093 // add it to the list of members
2094 TTypeLoc member = { new TType(EbtVoid), token.loc };
2095 member.type->shallowCopy(memberType);
2096 member.type->setFieldName(*idToken.string);
2097 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002098
John Kessenich54ee28f2017-03-11 14:13:00 -07002099 // array_specifier
2100 TArraySizes* arraySizes = nullptr;
2101 acceptArraySpecifier(arraySizes);
2102 if (arraySizes)
2103 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002104
John Kessenich54ee28f2017-03-11 14:13:00 -07002105 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002106
John Kessenich54ee28f2017-03-11 14:13:00 -07002107 // EQUAL assignment_expression
2108 if (acceptTokenClass(EHTokAssign)) {
2109 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2110 TIntermTyped* expressionNode = nullptr;
2111 if (! acceptAssignmentExpression(expressionNode)) {
2112 expected("initializer");
2113 return false;
2114 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002115 }
2116 }
John Kesseniche6e74942016-06-11 16:43:14 -06002117 // success on seeing the SEMICOLON coming up
2118 if (peekTokenClass(EHTokSemicolon))
2119 break;
2120
2121 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002122 if (acceptTokenClass(EHTokComma))
2123 declarator_list = true;
2124 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002125 expected(",");
2126 return false;
2127 }
2128
2129 } while (true);
2130
2131 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002132 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002133 expected(";");
2134 return false;
2135 }
2136
2137 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002138
John Kessenichb16f7e62017-03-11 19:32:47 -07002139 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002140}
2141
John Kessenich54ee28f2017-03-11 14:13:00 -07002142// member_function_definition
2143// | function_parameters post_decls compound_statement
2144//
2145// Expects type to have EvqGlobal for a static member and
2146// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002147bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2148 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002149{
John Kessenich54ee28f2017-03-11 14:13:00 -07002150 bool accepted = false;
2151
John Kessenich4dc835c2017-03-28 23:43:10 -06002152 const TString* functionName = &memberName;
2153 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002154 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002155 if (type.getQualifier().storage == EvqTemporary)
2156 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002157 else
2158 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002159
2160 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002161 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002162 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002163 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002164
2165 // compound_statement (function body definition)
2166 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002167 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002168 declarator.body = new TVector<HlslToken>;
2169 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002170 }
2171 } else
2172 expected("function parameter list");
2173
John Kessenich54ee28f2017-03-11 14:13:00 -07002174 return accepted;
2175}
2176
John Kessenich5f934b02016-03-13 17:58:25 -06002177// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002178// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002179// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002180//
2181bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2182{
John Kessenich078d7f22016-03-14 10:02:11 -06002183 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002184 if (! acceptTokenClass(EHTokLeftParen))
2185 return false;
2186
John Kessenich71351de2016-06-08 12:50:56 -06002187 // VOID RIGHT_PAREN
2188 if (! acceptTokenClass(EHTokVoid)) {
2189 do {
2190 // parameter_declaration
2191 if (! acceptParameterDeclaration(function))
2192 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002193
John Kessenich71351de2016-06-08 12:50:56 -06002194 // COMMA
2195 if (! acceptTokenClass(EHTokComma))
2196 break;
2197 } while (true);
2198 }
John Kessenich5f934b02016-03-13 17:58:25 -06002199
John Kessenich078d7f22016-03-14 10:02:11 -06002200 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002201 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002202 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002203 return false;
2204 }
2205
2206 return true;
2207}
2208
steve-lunarg26d31452016-12-23 18:56:57 -07002209// default_parameter_declaration
2210// : EQUAL conditional_expression
2211// : EQUAL initializer
2212bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2213{
2214 node = nullptr;
2215
2216 // Valid not to have a default_parameter_declaration
2217 if (!acceptTokenClass(EHTokAssign))
2218 return true;
2219
2220 if (!acceptConditionalExpression(node)) {
2221 if (!acceptInitializer(node))
2222 return false;
2223
2224 // For initializer lists, we have to const-fold into a constructor for the type, so build
2225 // that.
John Kessenichc633f642017-04-03 21:48:37 -06002226 TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
steve-lunarg26d31452016-12-23 18:56:57 -07002227 if (constructor == nullptr) // cannot construct
2228 return false;
2229
2230 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002231 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002232 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002233
steve-lunarg26d31452016-12-23 18:56:57 -07002234 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2235 }
2236
2237 // If this is simply a constant, we can use it directly.
2238 if (node->getAsConstantUnion())
2239 return true;
2240
2241 // Otherwise, it has to be const-foldable.
2242 TIntermTyped* origNode = node;
2243
2244 node = intermediate.fold(node->getAsAggregate());
2245
2246 if (node != nullptr && origNode != node)
2247 return true;
2248
2249 parseContext.error(token.loc, "invalid default parameter value", "", "");
2250
2251 return false;
2252}
2253
John Kessenich5f934b02016-03-13 17:58:25 -06002254// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002255// : fully_specified_type post_decls [ = default_parameter_declaration ]
2256// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002257//
2258bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2259{
2260 // fully_specified_type
2261 TType* type = new TType;
2262 if (! acceptFullySpecifiedType(*type))
2263 return false;
2264
2265 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002266 HlslToken idToken;
2267 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002268
John Kessenich19b92ff2016-06-19 11:50:34 -06002269 // array_specifier
2270 TArraySizes* arraySizes = nullptr;
2271 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002272 if (arraySizes) {
2273 if (arraySizes->isImplicit()) {
2274 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2275 return false;
2276 }
2277
John Kessenich19b92ff2016-06-19 11:50:34 -06002278 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002279 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002280
2281 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002282 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002283
steve-lunarg26d31452016-12-23 18:56:57 -07002284 TIntermTyped* defaultValue;
2285 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2286 return false;
2287
John Kessenich5aa59e22016-06-17 15:50:47 -06002288 parseContext.paramFix(*type);
2289
steve-lunarg26d31452016-12-23 18:56:57 -07002290 // If any prior parameters have default values, all the parameters after that must as well.
2291 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2292 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2293 return false;
2294 }
2295
2296 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002297 function.addParameter(param);
2298
2299 return true;
2300}
2301
2302// Do the work to create the function definition in addition to
2303// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002304//
2305// If 'deferredTokens' are passed in, just get the token stream,
2306// don't process.
2307//
2308bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2309 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002310{
John Kessenich088d52b2017-03-11 17:55:28 -07002311 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002312
John Kessenichb16f7e62017-03-11 19:32:47 -07002313 if (deferredTokens)
2314 return captureBlockTokens(*deferredTokens);
2315 else
John Kessenich4960baa2017-03-19 18:09:59 -06002316 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002317}
2318
2319bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2320{
2321 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002322 TIntermNode* entryPointNode = nullptr;
2323
John Kessenich077e0522016-06-09 02:02:17 -06002324 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002325 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2326 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002327
2328 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002329 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002330 if (! acceptCompoundStatement(functionBody))
2331 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002332
John Kessenich54ee28f2017-03-11 14:13:00 -07002333 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002334 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002335
2336 // Hook up the 1 or 2 function definitions.
2337 nodeList = intermediate.growAggregate(nodeList, functionNode);
2338 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002339
2340 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002341}
2342
John Kessenich0d2b6de2016-06-05 11:23:11 -06002343// Accept an expression with parenthesis around it, where
2344// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002345// syntactically required ones like in "if ( expression )".
2346//
2347// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002348//
2349// Note this one is not set up to be speculative; as it gives
2350// errors if not found.
2351//
2352bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2353{
2354 // LEFT_PAREN
2355 if (! acceptTokenClass(EHTokLeftParen))
2356 expected("(");
2357
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002358 bool decl = false;
2359 TIntermNode* declNode = nullptr;
2360 decl = acceptControlDeclaration(declNode);
2361 if (decl) {
2362 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2363 expected("initialized declaration");
2364 return false;
2365 } else
2366 expression = declNode->getAsTyped();
2367 } else {
2368 // no declaration
2369 if (! acceptExpression(expression)) {
2370 expected("expression");
2371 return false;
2372 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002373 }
2374
2375 // RIGHT_PAREN
2376 if (! acceptTokenClass(EHTokRightParen))
2377 expected(")");
2378
2379 return true;
2380}
2381
John Kessenich34fb0362016-05-03 23:17:20 -06002382// The top-level full expression recognizer.
2383//
John Kessenich87142c72016-03-12 20:24:24 -07002384// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002385// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002386//
2387bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2388{
LoopDawgef764a22016-06-03 09:17:51 -06002389 node = nullptr;
2390
John Kessenich34fb0362016-05-03 23:17:20 -06002391 // assignment_expression
2392 if (! acceptAssignmentExpression(node))
2393 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002394
John Kessenich34fb0362016-05-03 23:17:20 -06002395 if (! peekTokenClass(EHTokComma))
2396 return true;
2397
2398 do {
2399 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002400 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002401 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002402
John Kessenich34fb0362016-05-03 23:17:20 -06002403 // ... assignment_expression
2404 TIntermTyped* rightNode = nullptr;
2405 if (! acceptAssignmentExpression(rightNode)) {
2406 expected("assignment expression");
2407 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002408 }
2409
John Kessenich34fb0362016-05-03 23:17:20 -06002410 node = intermediate.addComma(node, rightNode, loc);
2411
2412 if (! peekTokenClass(EHTokComma))
2413 return true;
2414 } while (true);
2415}
2416
John Kessenich07354242016-07-01 19:58:06 -06002417// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002418// : LEFT_BRACE RIGHT_BRACE
2419// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002420//
2421// initializer_list
2422// : assignment_expression COMMA assignment_expression COMMA ...
2423//
2424bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2425{
2426 // LEFT_BRACE
2427 if (! acceptTokenClass(EHTokLeftBrace))
2428 return false;
2429
John Kessenich98ad4852016-11-27 17:39:07 -07002430 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002431 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002432 if (acceptTokenClass(EHTokRightBrace)) {
2433 // a zero-length initializer list
2434 node = intermediate.makeAggregate(loc);
2435 return true;
2436 }
2437
2438 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002439 node = nullptr;
2440 do {
2441 // assignment_expression
2442 TIntermTyped* expr;
2443 if (! acceptAssignmentExpression(expr)) {
2444 expected("assignment expression in initializer list");
2445 return false;
2446 }
2447 node = intermediate.growAggregate(node, expr, loc);
2448
2449 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002450 if (acceptTokenClass(EHTokComma)) {
2451 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2452 return true;
John Kessenich07354242016-07-01 19:58:06 -06002453 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002454 }
John Kessenich07354242016-07-01 19:58:06 -06002455
2456 // RIGHT_BRACE
2457 if (acceptTokenClass(EHTokRightBrace))
2458 return true;
2459
2460 expected(", or }");
2461 return false;
2462 } while (true);
2463}
2464
John Kessenich34fb0362016-05-03 23:17:20 -06002465// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002466// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002467//
2468// a op (b op (c op d))
2469//
2470// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002471// : initializer
2472// | conditional_expression
2473// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002474//
2475bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2476{
John Kessenich07354242016-07-01 19:58:06 -06002477 // initializer
2478 if (peekTokenClass(EHTokLeftBrace)) {
2479 if (acceptInitializer(node))
2480 return true;
2481
2482 expected("initializer");
2483 return false;
2484 }
2485
John Kessenich00957f82016-07-27 10:39:57 -06002486 // conditional_expression
2487 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002488 return false;
2489
John Kessenich07354242016-07-01 19:58:06 -06002490 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002491 TOperator assignOp = HlslOpMap::assignment(peek());
2492 if (assignOp == EOpNull)
2493 return true;
2494
John Kessenich00957f82016-07-27 10:39:57 -06002495 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002496 TSourceLoc loc = token.loc;
2497 advanceToken();
2498
John Kessenich00957f82016-07-27 10:39:57 -06002499 // conditional_expression assign_op conditional_expression ...
2500 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002501 // gets the right-to-left associativity.
2502 TIntermTyped* rightNode = nullptr;
2503 if (! acceptAssignmentExpression(rightNode)) {
2504 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002505 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002506 }
2507
John Kessenichd21baed2016-09-16 03:05:12 -06002508 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002509 node = parseContext.handleLvalue(loc, "assign", node);
2510
John Kessenichfea226b2016-07-28 17:53:56 -06002511 if (node == nullptr) {
2512 parseContext.error(loc, "could not create assignment", "", "");
2513 return false;
2514 }
John Kessenich34fb0362016-05-03 23:17:20 -06002515
2516 if (! peekTokenClass(EHTokComma))
2517 return true;
2518
2519 return true;
2520}
2521
John Kessenich00957f82016-07-27 10:39:57 -06002522// Accept a conditional expression, which associates right-to-left,
2523// accomplished by the "true" expression calling down to lower
2524// precedence levels than this level.
2525//
2526// conditional_expression
2527// : binary_expression
2528// | binary_expression QUESTION expression COLON assignment_expression
2529//
2530bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2531{
2532 // binary_expression
2533 if (! acceptBinaryExpression(node, PlLogicalOr))
2534 return false;
2535
2536 if (! acceptTokenClass(EHTokQuestion))
2537 return true;
2538
John Kessenich636b62d2017-04-11 19:45:00 -06002539 node = parseContext.convertConditionalExpression(token.loc, node, false);
John Kessenich7e997e22017-03-30 22:09:30 -06002540 if (node == nullptr)
2541 return false;
2542
John Kessenich00957f82016-07-27 10:39:57 -06002543 TIntermTyped* trueNode = nullptr;
2544 if (! acceptExpression(trueNode)) {
2545 expected("expression after ?");
2546 return false;
2547 }
2548 TSourceLoc loc = token.loc;
2549
2550 if (! acceptTokenClass(EHTokColon)) {
2551 expected(":");
2552 return false;
2553 }
2554
2555 TIntermTyped* falseNode = nullptr;
2556 if (! acceptAssignmentExpression(falseNode)) {
2557 expected("expression after :");
2558 return false;
2559 }
2560
2561 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2562
2563 return true;
2564}
2565
John Kessenich34fb0362016-05-03 23:17:20 -06002566// Accept a binary expression, for binary operations that
2567// associate left-to-right. This is, it is implicit, for example
2568//
2569// ((a op b) op c) op d
2570//
2571// binary_expression
2572// : expression op expression op expression ...
2573//
2574// where 'expression' is the next higher level in precedence.
2575//
2576bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2577{
2578 if (precedenceLevel > PlMul)
2579 return acceptUnaryExpression(node);
2580
2581 // assignment_expression
2582 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2583 return false;
2584
John Kessenich34fb0362016-05-03 23:17:20 -06002585 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002586 TOperator op = HlslOpMap::binary(peek());
2587 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2588 if (tokenLevel < precedenceLevel)
2589 return true;
2590
John Kessenich34fb0362016-05-03 23:17:20 -06002591 // ... op
2592 TSourceLoc loc = token.loc;
2593 advanceToken();
2594
2595 // ... expression
2596 TIntermTyped* rightNode = nullptr;
2597 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2598 expected("expression");
2599 return false;
2600 }
2601
2602 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002603 if (node == nullptr) {
2604 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2605 return false;
2606 }
John Kessenich34fb0362016-05-03 23:17:20 -06002607 } while (true);
2608}
2609
2610// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002611// : (type) unary_expression
2612// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002613// | - unary_expression
2614// | ! unary_expression
2615// | ~ unary_expression
2616// | ++ unary_expression
2617// | -- unary_expression
2618// | postfix_expression
2619//
2620bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2621{
John Kessenich1cc1a282016-06-03 16:55:49 -06002622 // (type) unary_expression
2623 // Have to look two steps ahead, because this could be, e.g., a
2624 // postfix_expression instead, since that also starts with at "(".
2625 if (acceptTokenClass(EHTokLeftParen)) {
2626 TType castType;
2627 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002628 if (acceptTokenClass(EHTokRightParen)) {
2629 // We've matched "(type)" now, get the expression to cast
2630 TSourceLoc loc = token.loc;
2631 if (! acceptUnaryExpression(node))
2632 return false;
2633
2634 // Hook it up like a constructor
John Kessenichc633f642017-04-03 21:48:37 -06002635 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
steve-lunarg5964c642016-07-30 07:38:55 -06002636 if (constructorFunction == nullptr) {
2637 expected("type that can be constructed");
2638 return false;
2639 }
2640 TIntermTyped* arguments = nullptr;
2641 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2642 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2643
2644 return true;
2645 } else {
2646 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2647 // the '(int' part. We must back up twice.
2648 recedeToken();
2649 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002650 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002651 } else {
2652 // This isn't a type cast, but it still started "(", so if it is a
2653 // unary expression, it can only be a postfix_expression, so try that.
2654 // Back it up first.
2655 recedeToken();
2656 return acceptPostfixExpression(node);
2657 }
2658 }
2659
2660 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002661 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002662
John Kessenich1cc1a282016-06-03 16:55:49 -06002663 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002664 if (unaryOp == EOpNull)
2665 return acceptPostfixExpression(node);
2666
2667 // op unary_expression
2668 TSourceLoc loc = token.loc;
2669 advanceToken();
2670 if (! acceptUnaryExpression(node))
2671 return false;
2672
2673 // + is a no-op
2674 if (unaryOp == EOpAdd)
2675 return true;
2676
2677 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002678
2679 // These unary ops require lvalues
2680 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2681 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002682
2683 return node != nullptr;
2684}
2685
2686// postfix_expression
2687// : LEFT_PAREN expression RIGHT_PAREN
2688// | literal
2689// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002690// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002691// | function_call
2692// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2693// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002694// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002695// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002696// | postfix_expression INC_OP
2697// | postfix_expression DEC_OP
2698//
2699bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2700{
2701 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002702 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002703
2704 // idToken will pick up either a variable or a function name in a function call
2705 HlslToken idToken;
2706
John Kessenich21472ae2016-06-04 11:46:33 -06002707 // Find something before the postfix operations, as they can't operate
2708 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002709 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002710 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002711 if (! acceptExpression(node)) {
2712 expected("expression");
2713 return false;
2714 }
2715 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002716 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002717 return false;
2718 }
John Kessenich34fb0362016-05-03 23:17:20 -06002719 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002720 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002721 } else if (acceptConstructor(node)) {
2722 // constructor (nothing else to do yet)
2723 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002724 // user-type, namespace name, variable, or function name
2725 TString* fullName = idToken.string;
2726 while (acceptTokenClass(EHTokColonColon)) {
2727 // user-type or namespace name
2728 fullName = NewPoolTString(fullName->c_str());
2729 fullName->append(parseContext.scopeMangler);
2730 if (acceptIdentifier(idToken))
2731 fullName->append(*idToken.string);
2732 else {
2733 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002734 return false;
2735 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002736 }
2737 if (! peekTokenClass(EHTokLeftParen)) {
2738 node = parseContext.handleVariable(idToken.loc, fullName);
2739 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002740 // function_call (nothing else to do yet)
2741 } else {
2742 expected("function call arguments");
2743 return false;
2744 }
John Kessenich21472ae2016-06-04 11:46:33 -06002745 } else {
2746 // nothing found, can't post operate
2747 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002748 }
2749
steve-lunarga2b01a02016-11-28 17:09:54 -07002750 // This is to guarantee we do this no matter how we get out of the stack frame.
2751 // This way there's no bug if an early return forgets to do it.
2752 struct tFinalize {
2753 tFinalize(HlslParseContext& p) : parseContext(p) { }
2754 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002755 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002756 private:
John Kessenichca71d942017-03-07 20:44:09 -07002757 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002758 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002759 } finalize(parseContext);
2760
2761 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2762 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2763 // level: hence the init and finalize. Even though in practice these must be
2764 // constants, they are parsed no matter what.
2765 parseContext.initFlattening();
2766
John Kessenich21472ae2016-06-04 11:46:33 -06002767 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002768 do {
2769 TSourceLoc loc = token.loc;
2770 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002771
John Kessenich34fb0362016-05-03 23:17:20 -06002772 // Consume only a valid post-unary operator, otherwise we are done.
2773 switch (postOp) {
2774 case EOpIndexDirectStruct:
2775 case EOpIndexIndirect:
2776 case EOpPostIncrement:
2777 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002778 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002779 advanceToken();
2780 break;
2781 default:
2782 return true;
2783 }
John Kessenich87142c72016-03-12 20:24:24 -07002784
John Kessenich34fb0362016-05-03 23:17:20 -06002785 // We have a valid post-unary operator, process it.
2786 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002787 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002788 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002789 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002790 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002791 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002792 HlslToken field;
2793 if (! acceptIdentifier(field)) {
2794 expected("swizzle or member");
2795 return false;
2796 }
LoopDawg4886f692016-06-29 10:58:58 -06002797
John Kessenich516d92d2017-03-08 20:09:03 -07002798 if (peekTokenClass(EHTokLeftParen)) {
2799 // member function
2800 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002801
John Kessenich516d92d2017-03-08 20:09:03 -07002802 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002803 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002804 expected("function parameters");
2805 return false;
2806 }
John Kessenich516d92d2017-03-08 20:09:03 -07002807 } else
2808 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002809
John Kessenich34fb0362016-05-03 23:17:20 -06002810 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002811 }
John Kessenich34fb0362016-05-03 23:17:20 -06002812 case EOpIndexIndirect:
2813 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002814 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002815 TIntermTyped* indexNode = nullptr;
2816 if (! acceptExpression(indexNode) ||
2817 ! peekTokenClass(EHTokRightBracket)) {
2818 expected("expression followed by ']'");
2819 return false;
2820 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002821 advanceToken();
2822 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
steve-lunarg2efd6c62017-04-06 20:22:20 -06002823 if (node == nullptr)
2824 return false;
John Kessenich19b92ff2016-06-19 11:50:34 -06002825 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002826 }
2827 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002828 // INC_OP
2829 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002830 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002831 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002832 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002833 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002834 break;
2835 default:
2836 assert(0);
2837 break;
2838 }
2839 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002840}
2841
John Kessenichd016be12016-03-13 11:24:20 -06002842// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002843// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002844//
2845bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2846{
2847 // type
2848 TType type;
2849 if (acceptType(type)) {
John Kessenichc633f642017-04-03 21:48:37 -06002850 TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
John Kessenichd016be12016-03-13 11:24:20 -06002851 if (constructorFunction == nullptr)
2852 return false;
2853
2854 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002855 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002856 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002857 // It's possible this is a type keyword used as an identifier. Put the token back
2858 // for later use.
2859 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002860 return false;
2861 }
2862
2863 // hook it up
2864 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2865
2866 return true;
2867 }
2868
2869 return false;
2870}
2871
John Kessenich34fb0362016-05-03 23:17:20 -06002872// The function_call identifier was already recognized, and passed in as idToken.
2873//
2874// function_call
2875// : [idToken] arguments
2876//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002877bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002878{
John Kessenich54ee28f2017-03-11 14:13:00 -07002879 // name
2880 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002881 if (baseObject == nullptr) {
2882 functionName = &name;
2883 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002884 // Built-in methods are not in the symbol table as methods, but as global functions
2885 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002886 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002887 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002888 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002889 if (! baseObject->getType().isStruct()) {
2890 expected("structure");
2891 return false;
2892 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002893 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002894 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002895 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002896 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002897 }
LoopDawg4886f692016-06-29 10:58:58 -06002898
John Kessenich54ee28f2017-03-11 14:13:00 -07002899 // function
2900 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2901
2902 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002903 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002904 if (baseObject != nullptr) {
2905 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002906 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002907 }
John Kessenich4678ca92016-05-13 09:33:42 -06002908 if (! acceptArguments(function, arguments))
2909 return false;
2910
John Kessenich54ee28f2017-03-11 14:13:00 -07002911 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002912 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002913
2914 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002915}
2916
John Kessenich87142c72016-03-12 20:24:24 -07002917// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002918// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002919//
John Kessenichd016be12016-03-13 11:24:20 -06002920// The arguments are pushed onto the 'function' argument list and
2921// onto the 'arguments' aggregate.
2922//
John Kessenich4678ca92016-05-13 09:33:42 -06002923bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002924{
John Kessenich078d7f22016-03-14 10:02:11 -06002925 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002926 if (! acceptTokenClass(EHTokLeftParen))
2927 return false;
2928
John Kessenich2aa12b12017-04-18 14:47:33 -06002929 // RIGHT_PAREN
2930 if (acceptTokenClass(EHTokRightParen))
2931 return true;
2932
2933 // must now be at least one expression...
John Kessenich87142c72016-03-12 20:24:24 -07002934 do {
John Kessenichd016be12016-03-13 11:24:20 -06002935 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002936 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002937 if (! acceptAssignmentExpression(arg))
John Kessenich2aa12b12017-04-18 14:47:33 -06002938 return false;
John Kessenichd016be12016-03-13 11:24:20 -06002939
2940 // hook it up
2941 parseContext.handleFunctionArgument(function, arguments, arg);
2942
John Kessenich078d7f22016-03-14 10:02:11 -06002943 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002944 if (! acceptTokenClass(EHTokComma))
2945 break;
2946 } while (true);
2947
John Kessenich078d7f22016-03-14 10:02:11 -06002948 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002949 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002950 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002951 return false;
2952 }
2953
2954 return true;
2955}
2956
2957bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2958{
2959 switch (token.tokenClass) {
2960 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002961 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002962 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002963 case EHTokUintConstant:
2964 node = intermediate.addConstantUnion(token.u, token.loc, true);
2965 break;
John Kessenich87142c72016-03-12 20:24:24 -07002966 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002967 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002968 break;
2969 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002970 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002971 break;
2972 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002973 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002974 break;
John Kessenich86f71382016-09-19 20:23:18 -06002975 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002976 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002977 break;
John Kessenich87142c72016-03-12 20:24:24 -07002978
2979 default:
2980 return false;
2981 }
2982
2983 advanceToken();
2984
2985 return true;
2986}
2987
John Kessenich5f934b02016-03-13 17:58:25 -06002988// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002989// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002990//
John Kessenich21472ae2016-06-04 11:46:33 -06002991bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002992{
John Kessenich21472ae2016-06-04 11:46:33 -06002993 TIntermAggregate* compoundStatement = nullptr;
2994
John Kessenich34fb0362016-05-03 23:17:20 -06002995 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002996 if (! acceptTokenClass(EHTokLeftBrace))
2997 return false;
2998
2999 // statement statement ...
3000 TIntermNode* statement = nullptr;
3001 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06003002 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
3003 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
3004 branch->getFlowOp() == EOpDefault)) {
3005 // hook up individual subsequences within a switch statement
3006 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
3007 compoundStatement = nullptr;
3008 } else {
3009 // hook it up to the growing compound statement
3010 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3011 }
John Kessenich5f934b02016-03-13 17:58:25 -06003012 }
John Kessenich34fb0362016-05-03 23:17:20 -06003013 if (compoundStatement)
3014 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06003015
John Kessenich21472ae2016-06-04 11:46:33 -06003016 retStatement = compoundStatement;
3017
John Kessenich34fb0362016-05-03 23:17:20 -06003018 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003019 return acceptTokenClass(EHTokRightBrace);
3020}
3021
John Kessenich0d2b6de2016-06-05 11:23:11 -06003022bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3023{
3024 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003025 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003026 parseContext.popScope();
3027
3028 return result;
3029}
3030
John Kessenich077e0522016-06-09 02:02:17 -06003031bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003032{
John Kessenich077e0522016-06-09 02:02:17 -06003033 parseContext.pushScope();
3034 bool result = acceptCompoundStatement(statement);
3035 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003036
3037 return result;
3038}
3039
John Kessenich5f934b02016-03-13 17:58:25 -06003040// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003041// : attributes attributed_statement
3042//
3043// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003044// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003045// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06003046// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06003047// | declaration_statement
3048// | selection_statement
3049// | switch_statement
3050// | case_label
3051// | iteration_statement
3052// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003053//
3054bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3055{
John Kessenich21472ae2016-06-04 11:46:33 -06003056 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003057
John Kessenich21472ae2016-06-04 11:46:33 -06003058 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003059 TAttributeMap attributes;
3060 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003061
John Kessenich21472ae2016-06-04 11:46:33 -06003062 // attributed_statement
3063 switch (peek()) {
3064 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003065 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003066
John Kessenich21472ae2016-06-04 11:46:33 -06003067 case EHTokIf:
3068 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003069
John Kessenich21472ae2016-06-04 11:46:33 -06003070 case EHTokSwitch:
3071 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003072
John Kessenich21472ae2016-06-04 11:46:33 -06003073 case EHTokFor:
3074 case EHTokDo:
3075 case EHTokWhile:
3076 return acceptIterationStatement(statement);
3077
3078 case EHTokContinue:
3079 case EHTokBreak:
3080 case EHTokDiscard:
3081 case EHTokReturn:
3082 return acceptJumpStatement(statement);
3083
3084 case EHTokCase:
3085 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003086 case EHTokDefault:
3087 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003088
3089 case EHTokSemicolon:
3090 return acceptTokenClass(EHTokSemicolon);
3091
3092 case EHTokRightBrace:
3093 // Performance: not strictly necessary, but stops a bunch of hunting early,
3094 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003095 return false;
3096
John Kessenich21472ae2016-06-04 11:46:33 -06003097 default:
3098 {
3099 // declaration
3100 if (acceptDeclaration(statement))
3101 return true;
3102
3103 // expression
3104 TIntermTyped* node;
3105 if (acceptExpression(node))
3106 statement = node;
3107 else
3108 return false;
3109
3110 // SEMICOLON (following an expression)
3111 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003112 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003113 return false;
3114 }
3115 }
3116 }
3117
John Kessenich5f934b02016-03-13 17:58:25 -06003118 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003119}
3120
John Kessenich21472ae2016-06-04 11:46:33 -06003121// attributes
3122// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3123//
3124// attribute:
3125// : UNROLL
3126// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3127// | FASTOPT
3128// | ALLOW_UAV_CONDITION
3129// | BRANCH
3130// | FLATTEN
3131// | FORCECASE
3132// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003133// | DOMAIN
3134// | EARLYDEPTHSTENCIL
3135// | INSTANCE
3136// | MAXTESSFACTOR
3137// | OUTPUTCONTROLPOINTS
3138// | OUTPUTTOPOLOGY
3139// | PARTITIONING
3140// | PATCHCONSTANTFUNC
3141// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003142//
steve-lunarg1868b142016-10-20 13:07:10 -06003143void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003144{
steve-lunarg1868b142016-10-20 13:07:10 -06003145 // For now, accept the [ XXX(X) ] syntax, but drop all but
3146 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003147 // TODO: subset to correct set? Pass on?
3148 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003149 HlslToken idToken;
3150
John Kessenich0d2b6de2016-06-05 11:23:11 -06003151 // LEFT_BRACKET?
3152 if (! acceptTokenClass(EHTokLeftBracket))
3153 return;
3154
3155 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003156 if (acceptIdentifier(idToken)) {
3157 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003158 } else if (! peekTokenClass(EHTokRightBracket)) {
3159 expected("identifier");
3160 advanceToken();
3161 }
3162
steve-lunarga22f7db2016-11-11 08:17:44 -07003163 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003164
3165 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003166 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003167 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003168
John Kessenich0d2b6de2016-06-05 11:23:11 -06003169 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003170 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003171
steve-lunarga22f7db2016-11-11 08:17:44 -07003172 while (acceptAssignmentExpression(node)) {
3173 expectingExpression = false;
3174 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003175 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003176 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003177 }
3178
steve-lunarga22f7db2016-11-11 08:17:44 -07003179 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003180 if (! acceptTokenClass(EHTokRightParen))
3181 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003182
3183 // Error for partial or missing expression
3184 if (expectingExpression || expressions->getSequence().empty())
3185 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003186 }
3187
3188 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003189 if (!acceptTokenClass(EHTokRightBracket)) {
3190 expected("]");
3191 return;
3192 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003193
steve-lunarg1868b142016-10-20 13:07:10 -06003194 // Add any values we found into the attribute map. This accepts
3195 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003196 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003197 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003198}
3199
John Kessenich0d2b6de2016-06-05 11:23:11 -06003200// selection_statement
3201// : IF LEFT_PAREN expression RIGHT_PAREN statement
3202// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3203//
John Kessenich21472ae2016-06-04 11:46:33 -06003204bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3205{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003206 TSourceLoc loc = token.loc;
3207
3208 // IF
3209 if (! acceptTokenClass(EHTokIf))
3210 return false;
3211
3212 // so that something declared in the condition is scoped to the lifetimes
3213 // of the then-else statements
3214 parseContext.pushScope();
3215
3216 // LEFT_PAREN expression RIGHT_PAREN
3217 TIntermTyped* condition;
3218 if (! acceptParenExpression(condition))
3219 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003220 condition = parseContext.convertConditionalExpression(loc, condition);
3221 if (condition == nullptr)
3222 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003223
3224 // create the child statements
3225 TIntermNodePair thenElse = { nullptr, nullptr };
3226
3227 // then statement
3228 if (! acceptScopedStatement(thenElse.node1)) {
3229 expected("then statement");
3230 return false;
3231 }
3232
3233 // ELSE
3234 if (acceptTokenClass(EHTokElse)) {
3235 // else statement
3236 if (! acceptScopedStatement(thenElse.node2)) {
3237 expected("else statement");
3238 return false;
3239 }
3240 }
3241
3242 // Put the pieces together
3243 statement = intermediate.addSelection(condition, thenElse, loc);
3244 parseContext.popScope();
3245
3246 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003247}
3248
John Kessenichd02dc5d2016-07-01 00:04:11 -06003249// switch_statement
3250// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3251//
John Kessenich21472ae2016-06-04 11:46:33 -06003252bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3253{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003254 // SWITCH
3255 TSourceLoc loc = token.loc;
3256 if (! acceptTokenClass(EHTokSwitch))
3257 return false;
3258
3259 // LEFT_PAREN expression RIGHT_PAREN
3260 parseContext.pushScope();
3261 TIntermTyped* switchExpression;
3262 if (! acceptParenExpression(switchExpression)) {
3263 parseContext.popScope();
3264 return false;
3265 }
3266
3267 // compound_statement
3268 parseContext.pushSwitchSequence(new TIntermSequence);
3269 bool statementOkay = acceptCompoundStatement(statement);
3270 if (statementOkay)
3271 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3272
3273 parseContext.popSwitchSequence();
3274 parseContext.popScope();
3275
3276 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003277}
3278
John Kessenich119f8f62016-06-05 15:44:07 -06003279// iteration_statement
3280// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3281// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3282// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3283//
3284// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003285bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3286{
John Kessenich119f8f62016-06-05 15:44:07 -06003287 TSourceLoc loc = token.loc;
3288 TIntermTyped* condition = nullptr;
3289
3290 EHlslTokenClass loop = peek();
3291 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3292
3293 // WHILE or DO or FOR
3294 advanceToken();
3295
3296 switch (loop) {
3297 case EHTokWhile:
3298 // so that something declared in the condition is scoped to the lifetime
3299 // of the while sub-statement
3300 parseContext.pushScope();
3301 parseContext.nestLooping();
3302
3303 // LEFT_PAREN condition RIGHT_PAREN
3304 if (! acceptParenExpression(condition))
3305 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003306 condition = parseContext.convertConditionalExpression(loc, condition);
3307 if (condition == nullptr)
3308 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003309
3310 // statement
3311 if (! acceptScopedStatement(statement)) {
3312 expected("while sub-statement");
3313 return false;
3314 }
3315
3316 parseContext.unnestLooping();
3317 parseContext.popScope();
3318
3319 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3320
3321 return true;
3322
3323 case EHTokDo:
3324 parseContext.nestLooping();
3325
3326 if (! acceptTokenClass(EHTokLeftBrace))
3327 expected("{");
3328
3329 // statement
3330 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3331 expected("do sub-statement");
3332 return false;
3333 }
3334
3335 if (! acceptTokenClass(EHTokRightBrace))
3336 expected("}");
3337
3338 // WHILE
3339 if (! acceptTokenClass(EHTokWhile)) {
3340 expected("while");
3341 return false;
3342 }
3343
3344 // LEFT_PAREN condition RIGHT_PAREN
3345 TIntermTyped* condition;
3346 if (! acceptParenExpression(condition))
3347 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003348 condition = parseContext.convertConditionalExpression(loc, condition);
3349 if (condition == nullptr)
3350 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003351
3352 if (! acceptTokenClass(EHTokSemicolon))
3353 expected(";");
3354
3355 parseContext.unnestLooping();
3356
3357 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3358
3359 return true;
3360
3361 case EHTokFor:
3362 {
3363 // LEFT_PAREN
3364 if (! acceptTokenClass(EHTokLeftParen))
3365 expected("(");
3366
3367 // so that something declared in the condition is scoped to the lifetime
3368 // of the for sub-statement
3369 parseContext.pushScope();
3370
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003371 // initializer
3372 TIntermNode* initNode = nullptr;
3373 if (! acceptControlDeclaration(initNode)) {
3374 TIntermTyped* initExpr = nullptr;
3375 acceptExpression(initExpr);
3376 initNode = initExpr;
3377 }
3378 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003379 if (! acceptTokenClass(EHTokSemicolon))
3380 expected(";");
3381
3382 parseContext.nestLooping();
3383
3384 // condition SEMI_COLON
3385 acceptExpression(condition);
3386 if (! acceptTokenClass(EHTokSemicolon))
3387 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003388 if (condition != nullptr) {
3389 condition = parseContext.convertConditionalExpression(loc, condition);
3390 if (condition == nullptr)
3391 return false;
3392 }
John Kessenich119f8f62016-06-05 15:44:07 -06003393
3394 // iterator SEMI_COLON
3395 TIntermTyped* iterator = nullptr;
3396 acceptExpression(iterator);
3397 if (! acceptTokenClass(EHTokRightParen))
3398 expected(")");
3399
3400 // statement
3401 if (! acceptScopedStatement(statement)) {
3402 expected("for sub-statement");
3403 return false;
3404 }
3405
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003406 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003407
3408 parseContext.popScope();
3409 parseContext.unnestLooping();
3410
3411 return true;
3412 }
3413
3414 default:
3415 return false;
3416 }
John Kessenich21472ae2016-06-04 11:46:33 -06003417}
3418
3419// jump_statement
3420// : CONTINUE SEMICOLON
3421// | BREAK SEMICOLON
3422// | DISCARD SEMICOLON
3423// | RETURN SEMICOLON
3424// | RETURN expression SEMICOLON
3425//
3426bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3427{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003428 EHlslTokenClass jump = peek();
3429 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003430 case EHTokContinue:
3431 case EHTokBreak:
3432 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003433 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003434 advanceToken();
3435 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003436 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003437 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003438 return false;
3439 }
John Kessenich21472ae2016-06-04 11:46:33 -06003440
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003441 switch (jump) {
3442 case EHTokContinue:
3443 statement = intermediate.addBranch(EOpContinue, token.loc);
3444 break;
3445 case EHTokBreak:
3446 statement = intermediate.addBranch(EOpBreak, token.loc);
3447 break;
3448 case EHTokDiscard:
3449 statement = intermediate.addBranch(EOpKill, token.loc);
3450 break;
3451
3452 case EHTokReturn:
3453 {
3454 // expression
3455 TIntermTyped* node;
3456 if (acceptExpression(node)) {
3457 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003458 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003459 } else
3460 statement = intermediate.addBranch(EOpReturn, token.loc);
3461 break;
3462 }
3463
3464 default:
3465 assert(0);
3466 return false;
3467 }
3468
3469 // SEMICOLON
3470 if (! acceptTokenClass(EHTokSemicolon))
3471 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003472
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003473 return true;
3474}
John Kessenich21472ae2016-06-04 11:46:33 -06003475
John Kessenichd02dc5d2016-07-01 00:04:11 -06003476// case_label
3477// : CASE expression COLON
3478//
John Kessenich21472ae2016-06-04 11:46:33 -06003479bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3480{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003481 TSourceLoc loc = token.loc;
3482 if (! acceptTokenClass(EHTokCase))
3483 return false;
3484
3485 TIntermTyped* expression;
3486 if (! acceptExpression(expression)) {
3487 expected("case expression");
3488 return false;
3489 }
3490
3491 if (! acceptTokenClass(EHTokColon)) {
3492 expected(":");
3493 return false;
3494 }
3495
3496 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3497
3498 return true;
3499}
3500
3501// default_label
3502// : DEFAULT COLON
3503//
3504bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3505{
3506 TSourceLoc loc = token.loc;
3507 if (! acceptTokenClass(EHTokDefault))
3508 return false;
3509
3510 if (! acceptTokenClass(EHTokColon)) {
3511 expected(":");
3512 return false;
3513 }
3514
3515 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3516
3517 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003518}
3519
John Kessenich19b92ff2016-06-19 11:50:34 -06003520// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003521// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3522// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003523//
3524void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3525{
3526 arraySizes = nullptr;
3527
steve-lunarg7b211a32016-10-13 12:26:18 -06003528 // Early-out if there aren't any array dimensions
3529 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003530 return;
3531
steve-lunarg7b211a32016-10-13 12:26:18 -06003532 // 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 -06003533 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003534
3535 // Collect each array dimension.
3536 while (acceptTokenClass(EHTokLeftBracket)) {
3537 TSourceLoc loc = token.loc;
3538 TIntermTyped* sizeExpr = nullptr;
3539
John Kessenich057df292017-03-06 18:18:37 -07003540 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003541 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3542
3543 if (! acceptTokenClass(EHTokRightBracket)) {
3544 expected("]");
3545 return;
3546 }
3547
3548 if (hasArraySize) {
3549 TArraySize arraySize;
3550 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3551 arraySizes->addInnerSize(arraySize);
3552 } else {
3553 arraySizes->addInnerSize(0); // sized by initializers.
3554 }
steve-lunarg265c0612016-09-27 10:57:35 -06003555 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003556}
3557
John Kessenich630dd7d2016-06-12 23:52:12 -06003558// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003559// : COLON semantic // optional
3560// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3561// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003562// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003563// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003564//
John Kessenich854fe242017-03-02 14:30:59 -07003565// Return true if any tokens were accepted. That is,
3566// false can be returned on successfully recognizing nothing,
3567// not necessarily meaning bad syntax.
3568//
3569bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003570{
John Kessenich854fe242017-03-02 14:30:59 -07003571 bool found = false;
3572
John Kessenich630dd7d2016-06-12 23:52:12 -06003573 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003574 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003575 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003576 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003577 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003578 if (peekTokenClass(EHTokLayout))
3579 acceptLayoutQualifierList(qualifier);
3580 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003581 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003582 if (! acceptTokenClass(EHTokLeftParen)) {
3583 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003584 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003585 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003586 HlslToken locationToken;
3587 if (! acceptIdentifier(locationToken)) {
3588 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003589 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003590 }
3591 HlslToken componentToken;
3592 if (acceptTokenClass(EHTokDot)) {
3593 if (! acceptIdentifier(componentToken)) {
3594 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003595 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003596 }
3597 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003598 if (! acceptTokenClass(EHTokRightParen)) {
3599 expected(")");
3600 break;
3601 }
John Kessenich7735b942016-09-05 12:40:06 -06003602 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003603 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003604 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003605 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003606 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003607 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3608 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003609 if (! acceptTokenClass(EHTokLeftParen)) {
3610 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003611 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003612 }
John Kessenichb38f0712016-07-30 10:29:54 -06003613 HlslToken registerDesc; // for Type#
3614 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003615 if (! acceptIdentifier(registerDesc)) {
3616 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003617 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003618 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003619 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3620 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003621 // Then we didn't really see the registerDesc yet, it was
3622 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003623 profile = registerDesc;
3624 if (! acceptIdentifier(registerDesc)) {
3625 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003626 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003627 }
3628 }
John Kessenichb38f0712016-07-30 10:29:54 -06003629 int subComponent = 0;
3630 if (acceptTokenClass(EHTokLeftBracket)) {
3631 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3632 if (! peekTokenClass(EHTokIntConstant)) {
3633 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003634 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003635 }
3636 subComponent = token.i;
3637 advanceToken();
3638 if (! acceptTokenClass(EHTokRightBracket)) {
3639 expected("]");
3640 break;
3641 }
3642 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003643 // (COMMA SPACEN)opt
3644 HlslToken spaceDesc;
3645 if (acceptTokenClass(EHTokComma)) {
3646 if (! acceptIdentifier(spaceDesc)) {
3647 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003648 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003649 }
3650 }
3651 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003652 if (! acceptTokenClass(EHTokRightParen)) {
3653 expected(")");
3654 break;
3655 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003656 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003657 } else {
3658 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003659 TString semanticUpperCase = *idToken.string;
3660 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3661 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003662 }
John Kessenich854fe242017-03-02 14:30:59 -07003663 } else if (peekTokenClass(EHTokLeftAngle)) {
3664 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003665 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003666 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003667 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003668
John Kessenich630dd7d2016-06-12 23:52:12 -06003669 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003670
3671 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003672}
3673
John Kessenichb16f7e62017-03-11 19:32:47 -07003674//
3675// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3676// processing.
3677//
3678bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3679{
3680 if (! peekTokenClass(EHTokLeftBrace))
3681 return false;
3682
3683 int braceCount = 0;
3684
3685 do {
3686 switch (peek()) {
3687 case EHTokLeftBrace:
3688 ++braceCount;
3689 break;
3690 case EHTokRightBrace:
3691 --braceCount;
3692 break;
3693 case EHTokNone:
3694 // End of input before balance { } is bad...
3695 return false;
3696 default:
3697 break;
3698 }
3699
3700 tokens.push_back(token);
3701 advanceToken();
3702 } while (braceCount > 0);
3703
3704 return true;
3705}
3706
John Kesseniche01a9bc2016-03-12 20:11:22 -07003707} // end namespace glslang