blob: 63b78bf3aed1a7c9f402e765b739da7a4f70a69d [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2016 Google, Inc.
3// Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kesseniche01a9bc2016-03-12 20:11:22 -07006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kesseniche01a9bc2016-03-12 20:11:22 -070010//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of Google, Inc., nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
John Kessenich927608b2017-01-06 12:34:14 -070023// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
John Kesseniche01a9bc2016-03-12 20:11:22 -070035//
36
John Kessenichd016be12016-03-13 11:24:20 -060037//
38// This is a set of mutually recursive methods implementing the HLSL grammar.
39// Generally, each returns
40// - through an argument: a type specifically appropriate to which rule it
41// recognized
42// - through the return value: true/false to indicate whether or not it
43// recognized its rule
44//
45// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060046// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060047// will build the AST.
48//
49// The next token, yet to be "accepted" is always sitting in 'token'.
50// When a method says it accepts a rule, that means all tokens involved
51// in the rule will have been consumed, and none left in 'token'.
52//
53
John Kesseniche01a9bc2016-03-12 20:11:22 -070054#include "hlslTokens.h"
55#include "hlslGrammar.h"
steve-lunarg1868b142016-10-20 13:07:10 -060056#include "hlslAttributes.h"
John Kesseniche01a9bc2016-03-12 20:11:22 -070057
58namespace glslang {
59
60// Root entry point to this recursive decent parser.
61// Return true if compilation unit was successfully accepted.
62bool HlslGrammar::parse()
63{
64 advanceToken();
65 return acceptCompilationUnit();
66}
67
68void HlslGrammar::expected(const char* syntax)
69{
70 parseContext.error(token.loc, "Expected", syntax, "");
71}
72
LoopDawg4886f692016-06-29 10:58:58 -060073void HlslGrammar::unimplemented(const char* error)
74{
75 parseContext.error(token.loc, "Unimplemented", error, "");
76}
77
John Kessenich7a41f962017-03-22 11:38:22 -060078// IDENTIFIER
79// THIS
80// type that can be used as IDENTIFIER
81//
John Kessenichaecd4972016-03-14 10:46:34 -060082// Only process the next token if it is an identifier.
83// Return true if it was an identifier.
84bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
85{
John Kessenich7a41f962017-03-22 11:38:22 -060086 // IDENTIFIER
John Kessenichaecd4972016-03-14 10:46:34 -060087 if (peekTokenClass(EHTokIdentifier)) {
88 idToken = token;
89 advanceToken();
90 return true;
91 }
92
John Kessenich7a41f962017-03-22 11:38:22 -060093 // THIS
94 // -> maps to the IDENTIFIER spelled with the internal special name for 'this'
95 if (peekTokenClass(EHTokThis)) {
96 idToken = token;
97 advanceToken();
98 idToken.tokenClass = EHTokIdentifier;
99 idToken.string = NewPoolTString(intermediate.implicitThisName);
100 return true;
101 }
102
103 // type that can be used as IDENTIFIER
104
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700105 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
106 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
107 // valid identifier, nor is "linear". This code special cases the known instances of this, so
108 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
John Kessenichecba76f2017-01-06 00:34:48 -0700109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 TString* idString = nullptr;
111 switch (peek()) {
112 case EHTokSample: idString = NewPoolTString("sample"); break;
113 case EHTokHalf: idString = NewPoolTString("half"); break;
114 case EHTokBool: idString = NewPoolTString("bool"); break;
115 case EHTokFloat: idString = NewPoolTString("float"); break;
116 case EHTokDouble: idString = NewPoolTString("double"); break;
117 case EHTokInt: idString = NewPoolTString("int"); break;
118 case EHTokUint: idString = NewPoolTString("uint"); break;
119 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
120 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
121 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
122 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
123 default:
124 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700125 }
126
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700127 token.string = idString;
128 token.tokenClass = EHTokIdentifier;
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700129 idToken = token;
130
131 advanceToken();
132
133 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600134}
135
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136// compilationUnit
John Kessenich8f9fdc92017-03-30 16:22:26 -0600137// : declaration_list EOF
John Kesseniche01a9bc2016-03-12 20:11:22 -0700138//
139bool HlslGrammar::acceptCompilationUnit()
140{
John Kessenichd016be12016-03-13 11:24:20 -0600141 TIntermNode* unitNode = nullptr;
142
John Kessenich8f9fdc92017-03-30 16:22:26 -0600143 if (! acceptDeclarationList(unitNode))
144 return false;
steve-lunargcb88de52016-08-03 07:04:18 -0600145
John Kessenich8f9fdc92017-03-30 16:22:26 -0600146 if (! peekTokenClass(EHTokNone))
147 return false;
John Kesseniche01a9bc2016-03-12 20:11:22 -0700148
John Kessenichd016be12016-03-13 11:24:20 -0600149 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700150 if (unitNode && !unitNode->getAsAggregate())
151 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600152 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600153
John Kesseniche01a9bc2016-03-12 20:11:22 -0700154 return true;
155}
156
John Kessenich8f9fdc92017-03-30 16:22:26 -0600157// Recognize the following, but with the extra condition that it can be
158// successfully terminated by EOF or '}'.
159//
160// declaration_list
161// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
162//
163// declaration_or_semicolon
164// : declaration
165// : SEMICOLON
166//
167bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
168{
169 do {
170 // HLSL allows extra semicolons between global declarations
171 do { } while (acceptTokenClass(EHTokSemicolon));
172
173 // EOF or RIGHT_BRACE
174 if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
175 return true;
176
177 // declaration
178 if (! acceptDeclaration(nodeList))
179 return false;
180 } while (true);
181
182 return true;
183}
184
LoopDawg4886f692016-06-29 10:58:58 -0600185// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700186// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600187//
188// sampler_state_assignment
189// : sampler_state_identifier EQUAL value SEMICOLON
190//
191// sampler_state_identifier
192// : ADDRESSU
193// | ADDRESSV
194// | ADDRESSW
195// | BORDERCOLOR
196// | FILTER
197// | MAXANISOTROPY
198// | MAXLOD
199// | MINLOD
200// | MIPLODBIAS
201//
202bool HlslGrammar::acceptSamplerState()
203{
204 // TODO: this should be genericized to accept a list of valid tokens and
205 // return token/value pairs. Presently it is specific to texture values.
206
207 if (! acceptTokenClass(EHTokLeftBrace))
208 return true;
209
210 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700211
LoopDawg4886f692016-06-29 10:58:58 -0600212 do {
213 // read state name
214 HlslToken state;
215 if (! acceptIdentifier(state))
216 break; // end of list
217
218 // FXC accepts any case
219 TString stateName = *state.string;
220 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
221
222 if (! acceptTokenClass(EHTokAssign)) {
223 expected("assign");
224 return false;
225 }
226
227 if (stateName == "minlod" || stateName == "maxlod") {
228 if (! peekTokenClass(EHTokIntConstant)) {
229 expected("integer");
230 return false;
231 }
232
233 TIntermTyped* lod = nullptr;
234 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
235 return false;
236 } else if (stateName == "maxanisotropy") {
237 if (! peekTokenClass(EHTokIntConstant)) {
238 expected("integer");
239 return false;
240 }
241
242 TIntermTyped* maxAnisotropy = nullptr;
243 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
244 return false;
245 } else if (stateName == "filter") {
246 HlslToken filterMode;
247 if (! acceptIdentifier(filterMode)) {
248 expected("filter mode");
249 return false;
250 }
251 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
252 HlslToken addrMode;
253 if (! acceptIdentifier(addrMode)) {
254 expected("texture address mode");
255 return false;
256 }
257 } else if (stateName == "miplodbias") {
258 TIntermTyped* lodBias = nullptr;
259 if (! acceptLiteral(lodBias)) {
260 expected("lod bias");
261 return false;
262 }
263 } else if (stateName == "bordercolor") {
264 return false;
265 } else {
266 expected("texture state");
267 return false;
268 }
269
270 // SEMICOLON
271 if (! acceptTokenClass(EHTokSemicolon)) {
272 expected("semicolon");
273 return false;
274 }
275 } while (true);
276
277 if (! acceptTokenClass(EHTokRightBrace))
278 return false;
279
280 return true;
281}
282
283// sampler_declaration_dx9
284// : SAMPLER identifier EQUAL sampler_type sampler_state
285//
John Kesseniche4821e42016-07-16 10:19:43 -0600286bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600287{
288 if (! acceptTokenClass(EHTokSampler))
289 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700290
LoopDawg4886f692016-06-29 10:58:58 -0600291 // TODO: remove this when DX9 style declarations are implemented.
292 unimplemented("Direct3D 9 sampler declaration");
293
294 // read sampler name
295 HlslToken name;
296 if (! acceptIdentifier(name)) {
297 expected("sampler name");
298 return false;
299 }
300
301 if (! acceptTokenClass(EHTokAssign)) {
302 expected("=");
303 return false;
304 }
305
306 return false;
307}
308
John Kesseniche01a9bc2016-03-12 20:11:22 -0700309// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600310// : sampler_declaration_dx9 post_decls SEMICOLON
John Kessenich13075c62017-04-11 09:51:32 -0600311// | fully_specified_type declarator_list SEMICOLON(optional for cbuffer/tbuffer)
John Kessenich630dd7d2016-06-12 23:52:12 -0600312// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600313// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600314// | typedef declaration
John Kessenich8f9fdc92017-03-30 16:22:26 -0600315// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
John Kessenich87142c72016-03-12 20:24:24 -0700316//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600317// declarator_list
318// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600319//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600320// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600321// : identifier array_specifier post_decls
322// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600323// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600324//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600325// Parsing has to go pretty far in to know whether it's a variable, prototype, or
326// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600327// as above. (The 'identifier' in the first item in init_declarator list is the
328// same as 'identifier' for function declarations.)
329//
John Kessenichca71d942017-03-07 20:44:09 -0700330// This can generate more than one subtree, one per initializer or a function body.
331// All initializer subtrees are put in their own aggregate node, making one top-level
332// node for all the initializers. Each function created is a top-level node to grow
333// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600334//
John Kessenichca71d942017-03-07 20:44:09 -0700335// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
336// each top-level node the declaration creates. Otherwise, if only one top-level
337// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700338//
John Kessenichca71d942017-03-07 20:44:09 -0700339bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700340{
John Kessenich8f9fdc92017-03-30 16:22:26 -0600341 // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
342 if (acceptTokenClass(EHTokNamespace)) {
343 HlslToken namespaceToken;
344 if (!acceptIdentifier(namespaceToken)) {
345 expected("namespace name");
346 return false;
347 }
348 parseContext.pushNamespace(*namespaceToken.string);
349 if (!acceptTokenClass(EHTokLeftBrace)) {
350 expected("{");
351 return false;
352 }
353 if (!acceptDeclarationList(nodeList)) {
354 expected("declaration list");
355 return false;
356 }
357 if (!acceptTokenClass(EHTokRightBrace)) {
358 expected("}");
359 return false;
360 }
361 parseContext.popNamespace();
362 return true;
363 }
364
John Kessenich54ee28f2017-03-11 14:13:00 -0700365 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600366
steve-lunarg1868b142016-10-20 13:07:10 -0600367 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700368 TFunctionDeclarator declarator;
369 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600370
John Kessenich5e69ec62016-07-05 00:02:40 -0600371 // typedef
372 bool typedefDecl = acceptTokenClass(EHTokTypedef);
373
John Kesseniche82061d2016-09-27 14:38:57 -0600374 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600375
376 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600377 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
378 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
379 // HLSL shaders, this will have to be a master level switch
380 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700381 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700382 // if (acceptSamplerDeclarationDX9(declaredType))
383 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600384
385 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700386 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700387 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600388
John Kessenich87142c72016-03-12 20:24:24 -0700389 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600390 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700391 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 while (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600393 const TString *fullName = idToken.string;
394 if (parseContext.symbolTable.atGlobalLevel())
395 parseContext.getFullNamespaceName(fullName);
John Kessenich78388722017-03-08 18:53:51 -0700396 if (peekTokenClass(EHTokLeftParen)) {
397 // looks like function parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600398
John Kessenich78388722017-03-08 18:53:51 -0700399 // Potentially rename shader entry point function. No-op most of the time.
John Kessenich8f9fdc92017-03-30 16:22:26 -0600400 parseContext.renameShaderFunction(fullName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600401
John Kessenich78388722017-03-08 18:53:51 -0700402 // function_parameters
John Kessenich8f9fdc92017-03-30 16:22:26 -0600403 declarator.function = new TFunction(fullName, declaredType);
John Kessenich088d52b2017-03-11 17:55:28 -0700404 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700405 expected("function parameter list");
406 return false;
407 }
408
John Kessenich630dd7d2016-06-12 23:52:12 -0600409 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700410 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600411
John Kessenichd5ed0b62016-07-04 17:32:45 -0600412 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700413 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600414 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700415 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600416 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600417 if (typedefDecl)
418 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700419 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600420 } else {
421 if (typedefDecl)
422 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700423 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600424 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600425 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600426 // A variable declaration. Fix the storage qualifier if it's a global.
427 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
428 declaredType.getQualifier().storage = EvqUniform;
429
John Kessenichecba76f2017-01-06 00:34:48 -0700430 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600431 // the number of types can expand when arrayness is different.
432 TType variableType;
433 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600434
John Kesseniche82061d2016-09-27 14:38:57 -0600435 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600436 TArraySizes* arraySizes = nullptr;
437 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600438
John Kesseniche82061d2016-09-27 14:38:57 -0600439 // Fix arrayness in the variableType
440 if (declaredType.isImplicitlySizedArray()) {
441 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
442 // of different sizes, for this case sharing the shallow copy of arrayness
443 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
444 variableType.newArraySizes(declaredType.getArraySizes());
445 }
446 if (arraySizes || variableType.isArray()) {
447 // In the most general case, arrayness is potentially coming both from the
448 // declared type and from the variable: "int[] a[];" or just one or the other.
449 // Merge it all to the variableType, so all arrayness is part of the variableType.
450 parseContext.arrayDimMerge(variableType, arraySizes);
451 }
452
LoopDawg4886f692016-06-29 10:58:58 -0600453 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600454 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600455 if (! acceptSamplerState())
456 return false;
457 }
458
John Kessenichd5ed0b62016-07-04 17:32:45 -0600459 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600460 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600461
462 // EQUAL assignment_expression
463 TIntermTyped* expressionNode = nullptr;
464 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600465 if (typedefDecl)
466 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600467 if (! acceptAssignmentExpression(expressionNode)) {
468 expected("initializer");
469 return false;
470 }
471 }
472
John Kessenich6dbc0a72016-09-27 19:13:05 -0600473 // TODO: things scoped within an annotation need their own name space;
474 // TODO: strings are not yet handled.
475 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
476 if (typedefDecl)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600477 parseContext.declareTypedef(idToken.loc, *fullName, variableType);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600478 else if (variableType.getBasicType() == EbtBlock) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600479 parseContext.declareBlock(idToken.loc, variableType, fullName);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600480 parseContext.declareStructBufferCounter(idToken.loc, variableType, *fullName);
481 } else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700482 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600483 // this isn't really an individual variable, but a member of the $Global buffer
John Kessenich8f9fdc92017-03-30 16:22:26 -0600484 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600485 } else {
486 // Declare the variable and add any initializer code to the AST.
487 // The top-level node is always made into an aggregate, as that's
488 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700489 initializers = intermediate.growAggregate(initializers,
John Kessenich8f9fdc92017-03-30 16:22:26 -0600490 parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
John Kessenichca71d942017-03-07 20:44:09 -0700491 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600492 }
493 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600494 }
John Kessenich5f934b02016-03-13 17:58:25 -0600495 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600496
497 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700498 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600499 continue;
500 }
501 };
502
John Kessenichca71d942017-03-07 20:44:09 -0700503 // The top-level initializer node is a sequence.
504 if (initializers != nullptr)
505 initializers->setOperator(EOpSequence);
506
507 // Add the initializers' aggregate to the nodeList we were handed.
508 if (nodeList)
509 nodeList = intermediate.growAggregate(nodeList, initializers);
510 else
511 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700512
John Kessenich13075c62017-04-11 09:51:32 -0600513 // SEMICOLON(optional for cbuffer/tbuffer)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600514 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich13075c62017-04-11 09:51:32 -0600515 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma) {
516 // This may have been a false detection of what appeared to be a declaration, but
517 // was actually an assignment such as "float = 4", where "float" is an identifier.
518 // We put the token back to let further parsing happen for cases where that may
519 // happen. This errors on the side of caution, and mostly triggers the error.
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700520 recedeToken();
John Kessenich13075c62017-04-11 09:51:32 -0600521 return false;
522 } else if (declaredType.getBasicType() == EbtBlock) {
523 // cbuffer, et. al. (but not struct) don't have an ending semicolon
524 return true;
525 } else {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700526 expected(";");
John Kessenich13075c62017-04-11 09:51:32 -0600527 return false;
528 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600529 }
John Kessenichecba76f2017-01-06 00:34:48 -0700530
John Kesseniche01a9bc2016-03-12 20:11:22 -0700531 return true;
532}
533
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600534// control_declaration
535// : fully_specified_type identifier EQUAL expression
536//
537bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
538{
539 node = nullptr;
540
541 // fully_specified_type
542 TType type;
543 if (! acceptFullySpecifiedType(type))
544 return false;
545
John Kessenich057df292017-03-06 18:18:37 -0700546 // filter out type casts
547 if (peekTokenClass(EHTokLeftParen)) {
548 recedeToken();
549 return false;
550 }
551
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600552 // identifier
553 HlslToken idToken;
554 if (! acceptIdentifier(idToken)) {
555 expected("identifier");
556 return false;
557 }
558
559 // EQUAL
560 TIntermTyped* expressionNode = nullptr;
561 if (! acceptTokenClass(EHTokAssign)) {
562 expected("=");
563 return false;
564 }
565
566 // expression
567 if (! acceptExpression(expressionNode)) {
568 expected("initializer");
569 return false;
570 }
571
John Kesseniche82061d2016-09-27 14:38:57 -0600572 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600573
574 return true;
575}
576
John Kessenich87142c72016-03-12 20:24:24 -0700577// fully_specified_type
578// : type_specifier
579// | type_qualifier type_specifier
580//
581bool HlslGrammar::acceptFullySpecifiedType(TType& type)
582{
John Kessenich54ee28f2017-03-11 14:13:00 -0700583 TIntermNode* nodeList = nullptr;
584 return acceptFullySpecifiedType(type, nodeList);
585}
586bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
587{
John Kessenich87142c72016-03-12 20:24:24 -0700588 // type_qualifier
589 TQualifier qualifier;
590 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600591 if (! acceptQualifier(qualifier))
592 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600593 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700594
595 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700596 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700597 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700598 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700599 // qualifier. Back it out, if we did.
600 if (qualifier.sample)
601 recedeToken();
602
John Kessenich87142c72016-03-12 20:24:24 -0700603 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700604 }
John Kessenich3d157c52016-07-25 16:05:33 -0600605 if (type.getBasicType() == EbtBlock) {
606 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600607 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600608 // further, it can create an anonymous instance of the block
John Kessenich13075c62017-04-11 09:51:32 -0600609 if (peek() != EHTokIdentifier)
John Kessenich3d157c52016-07-25 16:05:33 -0600610 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600611 } else {
612 // Some qualifiers are set when parsing the type. Merge those with
613 // whatever comes from acceptQualifier.
614 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700615
steve-lunargbb0183f2016-10-04 16:58:14 -0600616 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600617 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700618
steve-lunarg08e0c082017-03-29 20:01:13 -0600619 if (type.getQualifier().storage == EvqOut ||
steve-lunarg5da1f032017-02-12 17:50:28 -0700620 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700621 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700622 qualifier.readonly = type.getQualifier().readonly;
623 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700624
steve-lunarg08e0c082017-03-29 20:01:13 -0600625 if (type.getQualifier().builtIn != EbvNone)
626 qualifier.builtIn = type.getQualifier().builtIn;
627
steve-lunargf49cdf42016-11-17 15:04:20 -0700628 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600629 }
John Kessenich87142c72016-03-12 20:24:24 -0700630
631 return true;
632}
633
John Kessenich630dd7d2016-06-12 23:52:12 -0600634// type_qualifier
635// : qualifier qualifier ...
636//
637// Zero or more of these, so this can't return false.
638//
John Kessenichb9e39122016-08-17 10:22:08 -0600639bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700640{
John Kessenich630dd7d2016-06-12 23:52:12 -0600641 do {
642 switch (peek()) {
643 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600644 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600645 break;
646 case EHTokExtern:
647 // TODO: no meaning in glslang?
648 break;
649 case EHTokShared:
650 // TODO: hint
651 break;
652 case EHTokGroupShared:
653 qualifier.storage = EvqShared;
654 break;
655 case EHTokUniform:
656 qualifier.storage = EvqUniform;
657 break;
658 case EHTokConst:
659 qualifier.storage = EvqConst;
660 break;
661 case EHTokVolatile:
662 qualifier.volatil = true;
663 break;
664 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600665 qualifier.smooth = true;
666 break;
667 case EHTokCentroid:
668 qualifier.centroid = true;
669 break;
670 case EHTokNointerpolation:
671 qualifier.flat = true;
672 break;
673 case EHTokNoperspective:
674 qualifier.nopersp = true;
675 break;
676 case EHTokSample:
677 qualifier.sample = true;
678 break;
679 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600680 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600681 break;
682 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600683 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600684 break;
685 case EHTokPrecise:
686 qualifier.noContraction = true;
687 break;
LoopDawg9249c702016-07-12 20:44:32 -0600688 case EHTokIn:
689 qualifier.storage = EvqIn;
690 break;
691 case EHTokOut:
692 qualifier.storage = EvqOut;
693 break;
694 case EHTokInOut:
695 qualifier.storage = EvqInOut;
696 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600697 case EHTokLayout:
698 if (! acceptLayoutQualifierList(qualifier))
699 return false;
700 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700701 case EHTokGloballyCoherent:
702 qualifier.coherent = true;
703 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600704 case EHTokInline:
705 // TODO: map this to SPIR-V function control
706 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700707
708 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
709 // for output variables.
710 case EHTokPoint:
711 qualifier.storage = EvqIn;
712 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
713 return false;
714 break;
715 case EHTokLine:
716 qualifier.storage = EvqIn;
717 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
718 return false;
719 break;
720 case EHTokTriangle:
721 qualifier.storage = EvqIn;
722 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
723 return false;
724 break;
725 case EHTokLineAdj:
726 qualifier.storage = EvqIn;
727 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
728 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700729 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700730 case EHTokTriangleAdj:
731 qualifier.storage = EvqIn;
732 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
733 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700734 break;
735
John Kessenich630dd7d2016-06-12 23:52:12 -0600736 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600737 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600738 }
739 advanceToken();
740 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700741}
742
John Kessenichb9e39122016-08-17 10:22:08 -0600743// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600744// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600745//
746// layout_qualifier
747// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600748// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600749//
750// Zero or more of these, so this can't return false.
751//
752bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
753{
754 if (! acceptTokenClass(EHTokLayout))
755 return false;
756
757 // LEFT_PAREN
758 if (! acceptTokenClass(EHTokLeftParen))
759 return false;
760
761 do {
762 // identifier
763 HlslToken idToken;
764 if (! acceptIdentifier(idToken))
765 break;
766
767 // EQUAL expression
768 if (acceptTokenClass(EHTokAssign)) {
769 TIntermTyped* expr;
770 if (! acceptConditionalExpression(expr)) {
771 expected("expression");
772 return false;
773 }
774 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
775 } else
776 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
777
778 // COMMA
779 if (! acceptTokenClass(EHTokComma))
780 break;
781 } while (true);
782
783 // RIGHT_PAREN
784 if (! acceptTokenClass(EHTokRightParen)) {
785 expected(")");
786 return false;
787 }
788
789 return true;
790}
791
LoopDawg6daaa4f2016-06-23 19:13:48 -0600792// template_type
793// : FLOAT
794// | DOUBLE
795// | INT
796// | DWORD
797// | UINT
798// | BOOL
799//
steve-lunargf49cdf42016-11-17 15:04:20 -0700800bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600801{
802 switch (peek()) {
803 case EHTokFloat:
804 basicType = EbtFloat;
805 break;
806 case EHTokDouble:
807 basicType = EbtDouble;
808 break;
809 case EHTokInt:
810 case EHTokDword:
811 basicType = EbtInt;
812 break;
813 case EHTokUint:
814 basicType = EbtUint;
815 break;
816 case EHTokBool:
817 basicType = EbtBool;
818 break;
819 default:
820 return false;
821 }
822
823 advanceToken();
824
825 return true;
826}
827
828// vector_template_type
829// : VECTOR
830// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
831//
832bool HlslGrammar::acceptVectorTemplateType(TType& type)
833{
834 if (! acceptTokenClass(EHTokVector))
835 return false;
836
837 if (! acceptTokenClass(EHTokLeftAngle)) {
838 // in HLSL, 'vector' alone means float4.
839 new(&type) TType(EbtFloat, EvqTemporary, 4);
840 return true;
841 }
842
843 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700844 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600845 expected("scalar type");
846 return false;
847 }
848
849 // COMMA
850 if (! acceptTokenClass(EHTokComma)) {
851 expected(",");
852 return false;
853 }
854
855 // integer
856 if (! peekTokenClass(EHTokIntConstant)) {
857 expected("literal integer");
858 return false;
859 }
860
861 TIntermTyped* vecSize;
862 if (! acceptLiteral(vecSize))
863 return false;
864
865 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
866
867 new(&type) TType(basicType, EvqTemporary, vecSizeI);
868
869 if (vecSizeI == 1)
870 type.makeVector();
871
872 if (!acceptTokenClass(EHTokRightAngle)) {
873 expected("right angle bracket");
874 return false;
875 }
876
877 return true;
878}
879
880// matrix_template_type
881// : MATRIX
882// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
883//
884bool HlslGrammar::acceptMatrixTemplateType(TType& type)
885{
886 if (! acceptTokenClass(EHTokMatrix))
887 return false;
888
889 if (! acceptTokenClass(EHTokLeftAngle)) {
890 // in HLSL, 'matrix' alone means float4x4.
891 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
892 return true;
893 }
894
895 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700896 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600897 expected("scalar type");
898 return false;
899 }
900
901 // COMMA
902 if (! acceptTokenClass(EHTokComma)) {
903 expected(",");
904 return false;
905 }
906
907 // integer rows
908 if (! peekTokenClass(EHTokIntConstant)) {
909 expected("literal integer");
910 return false;
911 }
912
913 TIntermTyped* rows;
914 if (! acceptLiteral(rows))
915 return false;
916
917 // COMMA
918 if (! acceptTokenClass(EHTokComma)) {
919 expected(",");
920 return false;
921 }
John Kessenichecba76f2017-01-06 00:34:48 -0700922
LoopDawg6daaa4f2016-06-23 19:13:48 -0600923 // integer cols
924 if (! peekTokenClass(EHTokIntConstant)) {
925 expected("literal integer");
926 return false;
927 }
928
929 TIntermTyped* cols;
930 if (! acceptLiteral(cols))
931 return false;
932
933 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600934 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
935 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600936
937 if (!acceptTokenClass(EHTokRightAngle)) {
938 expected("right angle bracket");
939 return false;
940 }
941
942 return true;
943}
944
steve-lunargf49cdf42016-11-17 15:04:20 -0700945// layout_geometry
946// : LINESTREAM
947// | POINTSTREAM
948// | TRIANGLESTREAM
949//
950bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
951{
952 // read geometry type
953 const EHlslTokenClass geometryType = peek();
954
955 switch (geometryType) {
956 case EHTokPointStream: geometry = ElgPoints; break;
957 case EHTokLineStream: geometry = ElgLineStrip; break;
958 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
959 default:
960 return false; // not a layout geometry
961 }
962
963 advanceToken(); // consume the layout keyword
964 return true;
965}
966
steve-lunarg858c9282017-01-07 08:54:10 -0700967// tessellation_decl_type
968// : INPUTPATCH
969// | OUTPUTPATCH
970//
steve-lunarg067eb9b2017-04-01 15:34:48 -0600971bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
steve-lunarg858c9282017-01-07 08:54:10 -0700972{
973 // read geometry type
974 const EHlslTokenClass tessType = peek();
975
976 switch (tessType) {
steve-lunarg067eb9b2017-04-01 15:34:48 -0600977 case EHTokInputPatch: patchType = EbvInputPatch; break;
978 case EHTokOutputPatch: patchType = EbvOutputPatch; break;
steve-lunarg858c9282017-01-07 08:54:10 -0700979 default:
980 return false; // not a tessellation decl
981 }
982
983 advanceToken(); // consume the keyword
984 return true;
985}
986
987// tessellation_patch_template_type
988// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
989//
990bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
991{
steve-lunarg067eb9b2017-04-01 15:34:48 -0600992 TBuiltInVariable patchType;
993
994 if (! acceptTessellationDeclType(patchType))
steve-lunarg858c9282017-01-07 08:54:10 -0700995 return false;
996
997 if (! acceptTokenClass(EHTokLeftAngle))
998 return false;
999
1000 if (! acceptType(type)) {
1001 expected("tessellation patch type");
1002 return false;
1003 }
1004
1005 if (! acceptTokenClass(EHTokComma))
1006 return false;
1007
1008 // integer size
1009 if (! peekTokenClass(EHTokIntConstant)) {
1010 expected("literal integer");
1011 return false;
1012 }
1013
1014 TIntermTyped* size;
1015 if (! acceptLiteral(size))
1016 return false;
1017
1018 TArraySizes* arraySizes = new TArraySizes;
1019 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1020 type.newArraySizes(*arraySizes);
steve-lunarg067eb9b2017-04-01 15:34:48 -06001021 type.getQualifier().builtIn = patchType;
steve-lunarg858c9282017-01-07 08:54:10 -07001022
1023 if (! acceptTokenClass(EHTokRightAngle)) {
1024 expected("right angle bracket");
1025 return false;
1026 }
1027
1028 return true;
1029}
1030
steve-lunargf49cdf42016-11-17 15:04:20 -07001031// stream_out_template_type
1032// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1033//
1034bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1035{
1036 geometry = ElgNone;
1037
1038 if (! acceptOutputPrimitiveGeometry(geometry))
1039 return false;
1040
1041 if (! acceptTokenClass(EHTokLeftAngle))
1042 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001043
steve-lunargf49cdf42016-11-17 15:04:20 -07001044 if (! acceptType(type)) {
1045 expected("stream output type");
1046 return false;
1047 }
1048
steve-lunarg08e0c082017-03-29 20:01:13 -06001049 type.getQualifier().storage = EvqOut;
1050 type.getQualifier().builtIn = EbvGsOutputStream;
steve-lunargf49cdf42016-11-17 15:04:20 -07001051
1052 if (! acceptTokenClass(EHTokRightAngle)) {
1053 expected("right angle bracket");
1054 return false;
1055 }
1056
1057 return true;
1058}
John Kessenichecba76f2017-01-06 00:34:48 -07001059
John Kessenicha1e2d492016-09-20 13:22:58 -06001060// annotations
1061// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001062//
John Kessenicha1e2d492016-09-20 13:22:58 -06001063bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001064{
John Kessenicha1e2d492016-09-20 13:22:58 -06001065 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001066 return false;
1067
John Kessenicha1e2d492016-09-20 13:22:58 -06001068 // note that we are nesting a name space
1069 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001070
1071 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1072 do {
1073 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1074 while (acceptTokenClass(EHTokSemicolon))
1075 ;
1076
1077 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001078 break;
John Kessenich86f71382016-09-19 20:23:18 -06001079
1080 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001081 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001082 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001083 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001084 return false;
1085 }
1086 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001087
1088 parseContext.unnestAnnotations();
1089 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001090}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001091
LoopDawg4886f692016-06-29 10:58:58 -06001092// sampler_type
1093// : SAMPLER
1094// | SAMPLER1D
1095// | SAMPLER2D
1096// | SAMPLER3D
1097// | SAMPLERCUBE
1098// | SAMPLERSTATE
1099// | SAMPLERCOMPARISONSTATE
1100bool HlslGrammar::acceptSamplerType(TType& type)
1101{
1102 // read sampler type
1103 const EHlslTokenClass samplerType = peek();
1104
LoopDawga78b0292016-07-19 14:28:05 -06001105 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001106 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001107
LoopDawga78b0292016-07-19 14:28:05 -06001108 bool isShadow = false;
1109
LoopDawg4886f692016-06-29 10:58:58 -06001110 switch (samplerType) {
1111 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001112 case EHTokSampler1d: /*dim = Esd1D*/; break;
1113 case EHTokSampler2d: /*dim = Esd2D*/; break;
1114 case EHTokSampler3d: /*dim = Esd3D*/; break;
1115 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001116 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001117 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001118 default:
1119 return false; // not a sampler declaration
1120 }
1121
1122 advanceToken(); // consume the sampler type keyword
1123
1124 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001125
1126 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001127 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001128
1129 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1130
1131 return true;
1132}
1133
1134// texture_type
1135// | BUFFER
1136// | TEXTURE1D
1137// | TEXTURE1DARRAY
1138// | TEXTURE2D
1139// | TEXTURE2DARRAY
1140// | TEXTURE3D
1141// | TEXTURECUBE
1142// | TEXTURECUBEARRAY
1143// | TEXTURE2DMS
1144// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001145// | RWBUFFER
1146// | RWTEXTURE1D
1147// | RWTEXTURE1DARRAY
1148// | RWTEXTURE2D
1149// | RWTEXTURE2DARRAY
1150// | RWTEXTURE3D
1151
LoopDawg4886f692016-06-29 10:58:58 -06001152bool HlslGrammar::acceptTextureType(TType& type)
1153{
1154 const EHlslTokenClass textureType = peek();
1155
1156 TSamplerDim dim = EsdNone;
1157 bool array = false;
1158 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001159 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001160 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001161
1162 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001163 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001164 case EHTokTexture1d: dim = Esd1D; break;
1165 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1166 case EHTokTexture2d: dim = Esd2D; break;
1167 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1168 case EHTokTexture3d: dim = Esd3D; break;
1169 case EHTokTextureCube: dim = EsdCube; break;
1170 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1171 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1172 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1173 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1174 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1175 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1176 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1177 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1178 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001179 default:
1180 return false; // not a texture declaration
1181 }
1182
1183 advanceToken(); // consume the texture object keyword
1184
1185 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001186
LoopDawg4886f692016-06-29 10:58:58 -06001187 TIntermTyped* msCount = nullptr;
1188
steve-lunargbb0183f2016-10-04 16:58:14 -06001189 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001190 if (acceptTokenClass(EHTokLeftAngle)) {
1191 if (! acceptType(txType)) {
1192 expected("scalar or vector type");
1193 return false;
1194 }
1195
1196 const TBasicType basicRetType = txType.getBasicType() ;
1197
1198 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1199 unimplemented("basic type in texture");
1200 return false;
1201 }
1202
steve-lunargd53f7172016-07-27 15:46:48 -06001203 // Buffers can handle small mats if they fit in 4 components
1204 if (dim == EsdBuffer && txType.isMatrix()) {
1205 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1206 expected("components < 4 in matrix buffer type");
1207 return false;
1208 }
1209
1210 // TODO: except we don't handle it yet...
1211 unimplemented("matrix type in buffer");
1212 return false;
1213 }
1214
LoopDawg4886f692016-06-29 10:58:58 -06001215 if (!txType.isScalar() && !txType.isVector()) {
1216 expected("scalar or vector type");
1217 return false;
1218 }
1219
LoopDawg4886f692016-06-29 10:58:58 -06001220 if (ms && acceptTokenClass(EHTokComma)) {
1221 // read sample count for multisample types, if given
1222 if (! peekTokenClass(EHTokIntConstant)) {
1223 expected("multisample count");
1224 return false;
1225 }
1226
1227 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1228 return false;
1229 }
1230
1231 if (! acceptTokenClass(EHTokRightAngle)) {
1232 expected("right angle bracket");
1233 return false;
1234 }
1235 } else if (ms) {
1236 expected("texture type for multisample");
1237 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001238 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001239 expected("type for RWTexture/RWBuffer");
1240 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001241 }
1242
1243 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001244 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001245
1246 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001247 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001248
steve-lunarg4f2da272016-10-10 15:24:57 -06001249 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1250 if (image || dim == EsdBuffer)
1251 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001252
1253 // Non-image Buffers are combined
1254 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001255 sampler.set(txType.getBasicType(), dim, array);
1256 } else {
1257 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001258 if (image) {
1259 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1260 } else {
1261 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1262 }
steve-lunargd53f7172016-07-27 15:46:48 -06001263 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001264
1265 // Remember the declared vector size.
1266 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001267
steve-lunargbf1537f2017-03-31 17:40:09 -06001268 // Force uncombined, if necessary
1269 if (!combined)
1270 sampler.combined = false;
1271
LoopDawg4886f692016-06-29 10:58:58 -06001272 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001273 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001274
1275 return true;
1276}
1277
John Kessenich87142c72016-03-12 20:24:24 -07001278// If token is for a type, update 'type' with the type information,
1279// and return true and advance.
1280// Otherwise, return false, and don't advance
1281bool HlslGrammar::acceptType(TType& type)
1282{
John Kessenich54ee28f2017-03-11 14:13:00 -07001283 TIntermNode* nodeList = nullptr;
1284 return acceptType(type, nodeList);
1285}
1286bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1287{
steve-lunarg3226b082016-10-26 19:18:55 -06001288 // Basic types for min* types, broken out here in case of future
1289 // changes, e.g, to use native halfs.
1290 static const TBasicType min16float_bt = EbtFloat;
1291 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001292 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001293 static const TBasicType min16int_bt = EbtInt;
1294 static const TBasicType min12int_bt = EbtInt;
1295 static const TBasicType min16uint_bt = EbtUint;
1296
John Kessenich9c86c6a2016-05-03 22:49:24 -06001297 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001298 case EHTokVector:
1299 return acceptVectorTemplateType(type);
1300 break;
1301
1302 case EHTokMatrix:
1303 return acceptMatrixTemplateType(type);
1304 break;
1305
steve-lunargf49cdf42016-11-17 15:04:20 -07001306 case EHTokPointStream: // fall through
1307 case EHTokLineStream: // ...
1308 case EHTokTriangleStream: // ...
1309 {
1310 TLayoutGeometry geometry;
1311 if (! acceptStreamOutTemplateType(type, geometry))
1312 return false;
1313
1314 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1315 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001316
steve-lunargf49cdf42016-11-17 15:04:20 -07001317 return true;
1318 }
1319
steve-lunarg858c9282017-01-07 08:54:10 -07001320 case EHTokInputPatch: // fall through
1321 case EHTokOutputPatch: // ...
1322 {
1323 if (! acceptTessellationPatchTemplateType(type))
1324 return false;
1325
1326 return true;
1327 }
1328
LoopDawg4886f692016-06-29 10:58:58 -06001329 case EHTokSampler: // fall through
1330 case EHTokSampler1d: // ...
1331 case EHTokSampler2d: // ...
1332 case EHTokSampler3d: // ...
1333 case EHTokSamplerCube: // ...
1334 case EHTokSamplerState: // ...
1335 case EHTokSamplerComparisonState: // ...
1336 return acceptSamplerType(type);
1337 break;
1338
1339 case EHTokBuffer: // fall through
1340 case EHTokTexture1d: // ...
1341 case EHTokTexture1darray: // ...
1342 case EHTokTexture2d: // ...
1343 case EHTokTexture2darray: // ...
1344 case EHTokTexture3d: // ...
1345 case EHTokTextureCube: // ...
1346 case EHTokTextureCubearray: // ...
1347 case EHTokTexture2DMS: // ...
1348 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001349 case EHTokRWTexture1d: // ...
1350 case EHTokRWTexture1darray: // ...
1351 case EHTokRWTexture2d: // ...
1352 case EHTokRWTexture2darray: // ...
1353 case EHTokRWTexture3d: // ...
1354 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001355 return acceptTextureType(type);
1356 break;
1357
steve-lunarg5da1f032017-02-12 17:50:28 -07001358 case EHTokAppendStructuredBuffer:
1359 case EHTokByteAddressBuffer:
1360 case EHTokConsumeStructuredBuffer:
1361 case EHTokRWByteAddressBuffer:
1362 case EHTokRWStructuredBuffer:
1363 case EHTokStructuredBuffer:
1364 return acceptStructBufferType(type);
1365 break;
1366
John Kessenich27ffb292017-03-03 17:01:01 -07001367 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001368 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001369 case EHTokCBuffer:
1370 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001371 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001372
1373 case EHTokIdentifier:
1374 // An identifier could be for a user-defined type.
1375 // Note we cache the symbol table lookup, to save for a later rule
1376 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001377 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001378 advanceToken();
1379 return true;
1380 } else
1381 return false;
1382
John Kessenich71351de2016-06-08 12:50:56 -06001383 case EHTokVoid:
1384 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001385 break;
John Kessenich71351de2016-06-08 12:50:56 -06001386
John Kessenicha1e2d492016-09-20 13:22:58 -06001387 case EHTokString:
1388 new(&type) TType(EbtString);
1389 break;
1390
John Kessenich87142c72016-03-12 20:24:24 -07001391 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001392 new(&type) TType(EbtFloat);
1393 break;
John Kessenich87142c72016-03-12 20:24:24 -07001394 case EHTokFloat1:
1395 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001396 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001397 break;
John Kessenich87142c72016-03-12 20:24:24 -07001398 case EHTokFloat2:
1399 new(&type) TType(EbtFloat, EvqTemporary, 2);
1400 break;
1401 case EHTokFloat3:
1402 new(&type) TType(EbtFloat, EvqTemporary, 3);
1403 break;
1404 case EHTokFloat4:
1405 new(&type) TType(EbtFloat, EvqTemporary, 4);
1406 break;
1407
John Kessenich71351de2016-06-08 12:50:56 -06001408 case EHTokDouble:
1409 new(&type) TType(EbtDouble);
1410 break;
1411 case EHTokDouble1:
1412 new(&type) TType(EbtDouble);
1413 type.makeVector();
1414 break;
1415 case EHTokDouble2:
1416 new(&type) TType(EbtDouble, EvqTemporary, 2);
1417 break;
1418 case EHTokDouble3:
1419 new(&type) TType(EbtDouble, EvqTemporary, 3);
1420 break;
1421 case EHTokDouble4:
1422 new(&type) TType(EbtDouble, EvqTemporary, 4);
1423 break;
1424
1425 case EHTokInt:
1426 case EHTokDword:
1427 new(&type) TType(EbtInt);
1428 break;
1429 case EHTokInt1:
1430 new(&type) TType(EbtInt);
1431 type.makeVector();
1432 break;
John Kessenich87142c72016-03-12 20:24:24 -07001433 case EHTokInt2:
1434 new(&type) TType(EbtInt, EvqTemporary, 2);
1435 break;
1436 case EHTokInt3:
1437 new(&type) TType(EbtInt, EvqTemporary, 3);
1438 break;
1439 case EHTokInt4:
1440 new(&type) TType(EbtInt, EvqTemporary, 4);
1441 break;
1442
John Kessenich71351de2016-06-08 12:50:56 -06001443 case EHTokUint:
1444 new(&type) TType(EbtUint);
1445 break;
1446 case EHTokUint1:
1447 new(&type) TType(EbtUint);
1448 type.makeVector();
1449 break;
1450 case EHTokUint2:
1451 new(&type) TType(EbtUint, EvqTemporary, 2);
1452 break;
1453 case EHTokUint3:
1454 new(&type) TType(EbtUint, EvqTemporary, 3);
1455 break;
1456 case EHTokUint4:
1457 new(&type) TType(EbtUint, EvqTemporary, 4);
1458 break;
1459
1460 case EHTokBool:
1461 new(&type) TType(EbtBool);
1462 break;
1463 case EHTokBool1:
1464 new(&type) TType(EbtBool);
1465 type.makeVector();
1466 break;
John Kessenich87142c72016-03-12 20:24:24 -07001467 case EHTokBool2:
1468 new(&type) TType(EbtBool, EvqTemporary, 2);
1469 break;
1470 case EHTokBool3:
1471 new(&type) TType(EbtBool, EvqTemporary, 3);
1472 break;
1473 case EHTokBool4:
1474 new(&type) TType(EbtBool, EvqTemporary, 4);
1475 break;
1476
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001477 case EHTokHalf:
1478 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1479 break;
1480 case EHTokHalf1:
1481 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1482 type.makeVector();
1483 break;
1484 case EHTokHalf2:
1485 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1486 break;
1487 case EHTokHalf3:
1488 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1489 break;
1490 case EHTokHalf4:
1491 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1492 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001493
steve-lunarg3226b082016-10-26 19:18:55 -06001494 case EHTokMin16float:
1495 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1496 break;
1497 case EHTokMin16float1:
1498 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1499 type.makeVector();
1500 break;
1501 case EHTokMin16float2:
1502 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1503 break;
1504 case EHTokMin16float3:
1505 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1506 break;
1507 case EHTokMin16float4:
1508 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1509 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001510
steve-lunarg3226b082016-10-26 19:18:55 -06001511 case EHTokMin10float:
1512 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1513 break;
1514 case EHTokMin10float1:
1515 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1516 type.makeVector();
1517 break;
1518 case EHTokMin10float2:
1519 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1520 break;
1521 case EHTokMin10float3:
1522 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1523 break;
1524 case EHTokMin10float4:
1525 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1526 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001527
steve-lunarg3226b082016-10-26 19:18:55 -06001528 case EHTokMin16int:
1529 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1530 break;
1531 case EHTokMin16int1:
1532 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1533 type.makeVector();
1534 break;
1535 case EHTokMin16int2:
1536 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1537 break;
1538 case EHTokMin16int3:
1539 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1540 break;
1541 case EHTokMin16int4:
1542 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1543 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001544
steve-lunarg3226b082016-10-26 19:18:55 -06001545 case EHTokMin12int:
1546 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1547 break;
1548 case EHTokMin12int1:
1549 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1550 type.makeVector();
1551 break;
1552 case EHTokMin12int2:
1553 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1554 break;
1555 case EHTokMin12int3:
1556 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1557 break;
1558 case EHTokMin12int4:
1559 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1560 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001561
steve-lunarg3226b082016-10-26 19:18:55 -06001562 case EHTokMin16uint:
1563 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1564 break;
1565 case EHTokMin16uint1:
1566 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1567 type.makeVector();
1568 break;
1569 case EHTokMin16uint2:
1570 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1571 break;
1572 case EHTokMin16uint3:
1573 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1574 break;
1575 case EHTokMin16uint4:
1576 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1577 break;
1578
John Kessenich0133c122016-05-20 12:17:26 -06001579 case EHTokInt1x1:
1580 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1581 break;
1582 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001583 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001584 break;
1585 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001586 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001587 break;
1588 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001589 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001590 break;
1591 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001592 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001593 break;
1594 case EHTokInt2x2:
1595 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1596 break;
1597 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001598 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001599 break;
1600 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001601 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001602 break;
1603 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001604 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001605 break;
1606 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001607 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001608 break;
1609 case EHTokInt3x3:
1610 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1611 break;
1612 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001613 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001614 break;
1615 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001616 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001617 break;
1618 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001619 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001620 break;
1621 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001622 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001623 break;
1624 case EHTokInt4x4:
1625 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1626 break;
1627
John Kessenich71351de2016-06-08 12:50:56 -06001628 case EHTokUint1x1:
1629 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1630 break;
1631 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001632 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001633 break;
1634 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001635 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001636 break;
1637 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001638 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001639 break;
1640 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001641 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001642 break;
1643 case EHTokUint2x2:
1644 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1645 break;
1646 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001647 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001648 break;
1649 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001650 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001651 break;
1652 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001653 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001654 break;
1655 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001656 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001657 break;
1658 case EHTokUint3x3:
1659 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1660 break;
1661 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001662 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001663 break;
1664 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001665 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001666 break;
1667 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001668 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001669 break;
1670 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001671 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001672 break;
1673 case EHTokUint4x4:
1674 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1675 break;
1676
1677 case EHTokBool1x1:
1678 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1679 break;
1680 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001681 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001682 break;
1683 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001684 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001685 break;
1686 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001687 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001688 break;
1689 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001690 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001691 break;
1692 case EHTokBool2x2:
1693 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1694 break;
1695 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001696 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001697 break;
1698 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001699 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001700 break;
1701 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001702 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001703 break;
1704 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001705 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001706 break;
1707 case EHTokBool3x3:
1708 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1709 break;
1710 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001711 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001712 break;
1713 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001714 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001715 break;
1716 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001717 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001718 break;
1719 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001720 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001721 break;
1722 case EHTokBool4x4:
1723 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1724 break;
1725
John Kessenich0133c122016-05-20 12:17:26 -06001726 case EHTokFloat1x1:
1727 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1728 break;
1729 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001730 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001731 break;
1732 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001733 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001734 break;
1735 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001736 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001737 break;
1738 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001739 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001740 break;
John Kessenich87142c72016-03-12 20:24:24 -07001741 case EHTokFloat2x2:
1742 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1743 break;
1744 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001745 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001746 break;
1747 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001748 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001749 break;
John Kessenich0133c122016-05-20 12:17:26 -06001750 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001751 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001752 break;
John Kessenich87142c72016-03-12 20:24:24 -07001753 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001754 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001755 break;
1756 case EHTokFloat3x3:
1757 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1758 break;
1759 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001760 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001761 break;
John Kessenich0133c122016-05-20 12:17:26 -06001762 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001763 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001764 break;
John Kessenich87142c72016-03-12 20:24:24 -07001765 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001766 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001767 break;
1768 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001769 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001770 break;
1771 case EHTokFloat4x4:
1772 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1773 break;
1774
John Kessenich0133c122016-05-20 12:17:26 -06001775 case EHTokDouble1x1:
1776 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1777 break;
1778 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001779 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001780 break;
1781 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001782 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001783 break;
1784 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001785 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001786 break;
1787 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001788 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001789 break;
1790 case EHTokDouble2x2:
1791 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1792 break;
1793 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001794 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001795 break;
1796 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001797 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001798 break;
1799 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001800 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001801 break;
1802 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001803 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001804 break;
1805 case EHTokDouble3x3:
1806 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1807 break;
1808 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001809 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001810 break;
1811 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001812 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001813 break;
1814 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001815 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001816 break;
1817 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001818 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001819 break;
1820 case EHTokDouble4x4:
1821 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1822 break;
1823
John Kessenich87142c72016-03-12 20:24:24 -07001824 default:
1825 return false;
1826 }
1827
1828 advanceToken();
1829
1830 return true;
1831}
1832
John Kesseniche6e74942016-06-11 16:43:14 -06001833// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001834// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1835// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001836// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001837//
1838// struct_type
1839// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001840// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001841// | CBUFFER
1842// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001843//
John Kessenich54ee28f2017-03-11 14:13:00 -07001844bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001845{
John Kessenichb804de62016-09-05 12:19:18 -06001846 // This storage qualifier will tell us whether it's an AST
1847 // block type or just a generic structure type.
1848 TStorageQualifier storageQualifier = EvqTemporary;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001849 bool readonly = false;
John Kessenich3d157c52016-07-25 16:05:33 -06001850
1851 // CBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001852 if (acceptTokenClass(EHTokCBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001853 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001854 // TBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001855 } else if (acceptTokenClass(EHTokTBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001856 storageQualifier = EvqBuffer;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001857 readonly = true;
1858 }
John Kessenich27ffb292017-03-03 17:01:01 -07001859 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001860 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001861 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001862 return false;
1863
1864 // IDENTIFIER
1865 TString structName = "";
1866 if (peekTokenClass(EHTokIdentifier)) {
1867 structName = *token.string;
1868 advanceToken();
1869 }
1870
John Kessenich3d157c52016-07-25 16:05:33 -06001871 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001872 TQualifier postDeclQualifier;
1873 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001874 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001875
John Kessenichf3d88bd2017-03-19 12:24:29 -06001876 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001877 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001878 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001879 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1880 // struct_type IDENTIFIER
1881 return true;
1882 } else {
1883 expected("{");
1884 return false;
1885 }
John Kesseniche6e74942016-06-11 16:43:14 -06001886 }
1887
John Kessenichf3d88bd2017-03-19 12:24:29 -06001888
John Kesseniche6e74942016-06-11 16:43:14 -06001889 // struct_declaration_list
1890 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001891 // Save each member function so they can be processed after we have a fully formed 'this'.
1892 TVector<TFunctionDeclarator> functionDeclarators;
1893
1894 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001895 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001896 parseContext.popNamespace();
1897
1898 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001899 expected("struct member declarations");
1900 return false;
1901 }
1902
1903 // RIGHT_BRACE
1904 if (! acceptTokenClass(EHTokRightBrace)) {
1905 expected("}");
1906 return false;
1907 }
1908
1909 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001910 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001911 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001912 else {
John Kessenich7735b942016-09-05 12:40:06 -06001913 postDeclQualifier.storage = storageQualifier;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001914 postDeclQualifier.readonly = readonly;
John Kessenich7735b942016-09-05 12:40:06 -06001915 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001916 }
John Kesseniche6e74942016-06-11 16:43:14 -06001917
John Kessenich727b3742017-02-03 17:57:55 -07001918 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001919
John Kessenich4960baa2017-03-19 18:09:59 -06001920 // For member functions: now that we know the type of 'this', go back and
1921 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1922 // - parse the functions, their tokens were saved for deferred parsing (now)
1923 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1924 // update signature
1925 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001926 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001927 }
1928
John Kessenichf3d88bd2017-03-19 12:24:29 -06001929 // All member functions get parsed inside the class/struct namespace and with the
1930 // class/struct members in a symbol-table level.
1931 parseContext.pushNamespace(structName);
John Kessenich37789792017-03-21 23:56:40 -06001932 parseContext.pushThisScope(type);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001933 bool deferredSuccess = true;
1934 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1935 // parse body
1936 pushTokenStream(functionDeclarators[b].body);
1937 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1938 deferredSuccess = false;
1939 popTokenStream();
1940 }
John Kessenich37789792017-03-21 23:56:40 -06001941 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001942 parseContext.popNamespace();
1943
1944 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001945}
1946
steve-lunarg5da1f032017-02-12 17:50:28 -07001947// struct_buffer
1948// : APPENDSTRUCTUREDBUFFER
1949// | BYTEADDRESSBUFFER
1950// | CONSUMESTRUCTUREDBUFFER
1951// | RWBYTEADDRESSBUFFER
1952// | RWSTRUCTUREDBUFFER
1953// | STRUCTUREDBUFFER
1954bool HlslGrammar::acceptStructBufferType(TType& type)
1955{
1956 const EHlslTokenClass structBuffType = peek();
1957
1958 // TODO: globallycoherent
1959 bool hasTemplateType = true;
1960 bool readonly = false;
1961
1962 TStorageQualifier storage = EvqBuffer;
steve-lunarg8e26feb2017-04-10 08:19:21 -06001963 TBuiltInVariable builtinType = EbvNone;
steve-lunarg5da1f032017-02-12 17:50:28 -07001964
1965 switch (structBuffType) {
1966 case EHTokAppendStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06001967 builtinType = EbvAppendConsume;
1968 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07001969 case EHTokByteAddressBuffer:
1970 hasTemplateType = false;
1971 readonly = true;
steve-lunarg8e26feb2017-04-10 08:19:21 -06001972 builtinType = EbvByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07001973 break;
1974 case EHTokConsumeStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06001975 builtinType = EbvAppendConsume;
1976 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07001977 case EHTokRWByteAddressBuffer:
1978 hasTemplateType = false;
steve-lunarg8e26feb2017-04-10 08:19:21 -06001979 builtinType = EbvRWByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07001980 break;
1981 case EHTokRWStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06001982 builtinType = EbvRWStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07001983 break;
1984 case EHTokStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06001985 builtinType = EbvStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07001986 readonly = true;
1987 break;
1988 default:
1989 return false; // not a structure buffer type
1990 }
1991
1992 advanceToken(); // consume the structure keyword
1993
1994 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1995 TType* templateType = new TType;
1996
1997 if (hasTemplateType) {
1998 if (! acceptTokenClass(EHTokLeftAngle)) {
1999 expected("left angle bracket");
2000 return false;
2001 }
2002
2003 if (! acceptType(*templateType)) {
2004 expected("type");
2005 return false;
2006 }
2007 if (! acceptTokenClass(EHTokRightAngle)) {
2008 expected("right angle bracket");
2009 return false;
2010 }
2011 } else {
2012 // byte address buffers have no explicit type.
2013 TType uintType(EbtUint, storage);
2014 templateType->shallowCopy(uintType);
2015 }
2016
2017 // Create an unsized array out of that type.
2018 // TODO: does this work if it's already an array type?
2019 TArraySizes unsizedArray;
2020 unsizedArray.addInnerSize(UnsizedArraySize);
2021 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002022 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002023
2024 // field name is canonical for all structbuffers
2025 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002026
steve-lunarg5da1f032017-02-12 17:50:28 -07002027 TTypeList* blockStruct = new TTypeList;
2028 TTypeLoc member = { templateType, token.loc };
2029 blockStruct->push_back(member);
2030
steve-lunargdd8287a2017-02-23 18:04:12 -07002031 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002032 TType blockType(blockStruct, "", templateType->getQualifier());
2033
steve-lunargdd8287a2017-02-23 18:04:12 -07002034 blockType.getQualifier().storage = storage;
2035 blockType.getQualifier().readonly = readonly;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002036 blockType.getQualifier().builtIn = builtinType;
steve-lunargdd8287a2017-02-23 18:04:12 -07002037
2038 // We may have created an equivalent type before, in which case we should use its
2039 // deep structure.
2040 parseContext.shareStructBufferType(blockType);
2041
steve-lunarg5da1f032017-02-12 17:50:28 -07002042 type.shallowCopy(blockType);
2043
2044 return true;
2045}
2046
John Kesseniche6e74942016-06-11 16:43:14 -06002047// struct_declaration_list
2048// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2049//
2050// struct_declaration
2051// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002052// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002053//
2054// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002055// : IDENTIFIER post_decls
2056// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002057// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002058//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002059bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002060 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002061{
2062 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002063 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002064
2065 do {
2066 // success on seeing the RIGHT_BRACE coming up
2067 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002068 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002069
2070 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002071
2072 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002073
2074 // fully_specified_type
2075 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002076 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002077 expected("member type");
2078 return false;
2079 }
2080
2081 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002082 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002083 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002084 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002085 expected("member name");
2086 return false;
2087 }
2088
John Kessenich54ee28f2017-03-11 14:13:00 -07002089 if (peekTokenClass(EHTokLeftParen)) {
2090 // function_parameters
2091 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002092 declarators.resize(declarators.size() + 1);
2093 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002094 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2095 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002096 if (functionDefinitionAccepted)
2097 break;
2098 }
2099 expected("member-function definition");
2100 return false;
2101 } else {
2102 // add it to the list of members
2103 TTypeLoc member = { new TType(EbtVoid), token.loc };
2104 member.type->shallowCopy(memberType);
2105 member.type->setFieldName(*idToken.string);
2106 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002107
John Kessenich54ee28f2017-03-11 14:13:00 -07002108 // array_specifier
2109 TArraySizes* arraySizes = nullptr;
2110 acceptArraySpecifier(arraySizes);
2111 if (arraySizes)
2112 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002113
John Kessenich54ee28f2017-03-11 14:13:00 -07002114 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002115
John Kessenich54ee28f2017-03-11 14:13:00 -07002116 // EQUAL assignment_expression
2117 if (acceptTokenClass(EHTokAssign)) {
2118 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2119 TIntermTyped* expressionNode = nullptr;
2120 if (! acceptAssignmentExpression(expressionNode)) {
2121 expected("initializer");
2122 return false;
2123 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002124 }
2125 }
John Kesseniche6e74942016-06-11 16:43:14 -06002126 // success on seeing the SEMICOLON coming up
2127 if (peekTokenClass(EHTokSemicolon))
2128 break;
2129
2130 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002131 if (acceptTokenClass(EHTokComma))
2132 declarator_list = true;
2133 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002134 expected(",");
2135 return false;
2136 }
2137
2138 } while (true);
2139
2140 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002141 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002142 expected(";");
2143 return false;
2144 }
2145
2146 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002147
John Kessenichb16f7e62017-03-11 19:32:47 -07002148 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002149}
2150
John Kessenich54ee28f2017-03-11 14:13:00 -07002151// member_function_definition
2152// | function_parameters post_decls compound_statement
2153//
2154// Expects type to have EvqGlobal for a static member and
2155// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002156bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2157 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002158{
John Kessenich54ee28f2017-03-11 14:13:00 -07002159 bool accepted = false;
2160
John Kessenich4dc835c2017-03-28 23:43:10 -06002161 const TString* functionName = &memberName;
2162 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002163 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002164 if (type.getQualifier().storage == EvqTemporary)
2165 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002166 else
2167 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002168
2169 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002170 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002171 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002172 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002173
2174 // compound_statement (function body definition)
2175 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002176 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002177 declarator.body = new TVector<HlslToken>;
2178 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002179 }
2180 } else
2181 expected("function parameter list");
2182
John Kessenich54ee28f2017-03-11 14:13:00 -07002183 return accepted;
2184}
2185
John Kessenich5f934b02016-03-13 17:58:25 -06002186// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002187// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002188// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002189//
2190bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2191{
John Kessenich078d7f22016-03-14 10:02:11 -06002192 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002193 if (! acceptTokenClass(EHTokLeftParen))
2194 return false;
2195
John Kessenich71351de2016-06-08 12:50:56 -06002196 // VOID RIGHT_PAREN
2197 if (! acceptTokenClass(EHTokVoid)) {
2198 do {
2199 // parameter_declaration
2200 if (! acceptParameterDeclaration(function))
2201 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002202
John Kessenich71351de2016-06-08 12:50:56 -06002203 // COMMA
2204 if (! acceptTokenClass(EHTokComma))
2205 break;
2206 } while (true);
2207 }
John Kessenich5f934b02016-03-13 17:58:25 -06002208
John Kessenich078d7f22016-03-14 10:02:11 -06002209 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002210 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002211 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002212 return false;
2213 }
2214
2215 return true;
2216}
2217
steve-lunarg26d31452016-12-23 18:56:57 -07002218// default_parameter_declaration
2219// : EQUAL conditional_expression
2220// : EQUAL initializer
2221bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2222{
2223 node = nullptr;
2224
2225 // Valid not to have a default_parameter_declaration
2226 if (!acceptTokenClass(EHTokAssign))
2227 return true;
2228
2229 if (!acceptConditionalExpression(node)) {
2230 if (!acceptInitializer(node))
2231 return false;
2232
2233 // For initializer lists, we have to const-fold into a constructor for the type, so build
2234 // that.
John Kessenichc633f642017-04-03 21:48:37 -06002235 TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
steve-lunarg26d31452016-12-23 18:56:57 -07002236 if (constructor == nullptr) // cannot construct
2237 return false;
2238
2239 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002240 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002241 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002242
steve-lunarg26d31452016-12-23 18:56:57 -07002243 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2244 }
2245
2246 // If this is simply a constant, we can use it directly.
2247 if (node->getAsConstantUnion())
2248 return true;
2249
2250 // Otherwise, it has to be const-foldable.
2251 TIntermTyped* origNode = node;
2252
2253 node = intermediate.fold(node->getAsAggregate());
2254
2255 if (node != nullptr && origNode != node)
2256 return true;
2257
2258 parseContext.error(token.loc, "invalid default parameter value", "", "");
2259
2260 return false;
2261}
2262
John Kessenich5f934b02016-03-13 17:58:25 -06002263// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002264// : fully_specified_type post_decls [ = default_parameter_declaration ]
2265// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002266//
2267bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2268{
2269 // fully_specified_type
2270 TType* type = new TType;
2271 if (! acceptFullySpecifiedType(*type))
2272 return false;
2273
2274 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002275 HlslToken idToken;
2276 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002277
John Kessenich19b92ff2016-06-19 11:50:34 -06002278 // array_specifier
2279 TArraySizes* arraySizes = nullptr;
2280 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002281 if (arraySizes) {
2282 if (arraySizes->isImplicit()) {
2283 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2284 return false;
2285 }
2286
John Kessenich19b92ff2016-06-19 11:50:34 -06002287 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002288 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002289
2290 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002291 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002292
steve-lunarg26d31452016-12-23 18:56:57 -07002293 TIntermTyped* defaultValue;
2294 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2295 return false;
2296
John Kessenich5aa59e22016-06-17 15:50:47 -06002297 parseContext.paramFix(*type);
2298
steve-lunarg26d31452016-12-23 18:56:57 -07002299 // If any prior parameters have default values, all the parameters after that must as well.
2300 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2301 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2302 return false;
2303 }
2304
2305 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002306 function.addParameter(param);
2307
2308 return true;
2309}
2310
2311// Do the work to create the function definition in addition to
2312// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002313//
2314// If 'deferredTokens' are passed in, just get the token stream,
2315// don't process.
2316//
2317bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2318 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002319{
John Kessenich088d52b2017-03-11 17:55:28 -07002320 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002321
John Kessenichb16f7e62017-03-11 19:32:47 -07002322 if (deferredTokens)
2323 return captureBlockTokens(*deferredTokens);
2324 else
John Kessenich4960baa2017-03-19 18:09:59 -06002325 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002326}
2327
2328bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2329{
2330 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002331 TIntermNode* entryPointNode = nullptr;
2332
John Kessenich077e0522016-06-09 02:02:17 -06002333 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002334 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2335 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002336
2337 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002338 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002339 if (! acceptCompoundStatement(functionBody))
2340 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002341
John Kessenich54ee28f2017-03-11 14:13:00 -07002342 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002343 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002344
2345 // Hook up the 1 or 2 function definitions.
2346 nodeList = intermediate.growAggregate(nodeList, functionNode);
2347 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002348
2349 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002350}
2351
John Kessenich0d2b6de2016-06-05 11:23:11 -06002352// Accept an expression with parenthesis around it, where
2353// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002354// syntactically required ones like in "if ( expression )".
2355//
2356// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002357//
2358// Note this one is not set up to be speculative; as it gives
2359// errors if not found.
2360//
2361bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2362{
2363 // LEFT_PAREN
2364 if (! acceptTokenClass(EHTokLeftParen))
2365 expected("(");
2366
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002367 bool decl = false;
2368 TIntermNode* declNode = nullptr;
2369 decl = acceptControlDeclaration(declNode);
2370 if (decl) {
2371 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2372 expected("initialized declaration");
2373 return false;
2374 } else
2375 expression = declNode->getAsTyped();
2376 } else {
2377 // no declaration
2378 if (! acceptExpression(expression)) {
2379 expected("expression");
2380 return false;
2381 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002382 }
2383
2384 // RIGHT_PAREN
2385 if (! acceptTokenClass(EHTokRightParen))
2386 expected(")");
2387
2388 return true;
2389}
2390
John Kessenich34fb0362016-05-03 23:17:20 -06002391// The top-level full expression recognizer.
2392//
John Kessenich87142c72016-03-12 20:24:24 -07002393// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002394// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002395//
2396bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2397{
LoopDawgef764a22016-06-03 09:17:51 -06002398 node = nullptr;
2399
John Kessenich34fb0362016-05-03 23:17:20 -06002400 // assignment_expression
2401 if (! acceptAssignmentExpression(node))
2402 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002403
John Kessenich34fb0362016-05-03 23:17:20 -06002404 if (! peekTokenClass(EHTokComma))
2405 return true;
2406
2407 do {
2408 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002409 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002410 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002411
John Kessenich34fb0362016-05-03 23:17:20 -06002412 // ... assignment_expression
2413 TIntermTyped* rightNode = nullptr;
2414 if (! acceptAssignmentExpression(rightNode)) {
2415 expected("assignment expression");
2416 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002417 }
2418
John Kessenich34fb0362016-05-03 23:17:20 -06002419 node = intermediate.addComma(node, rightNode, loc);
2420
2421 if (! peekTokenClass(EHTokComma))
2422 return true;
2423 } while (true);
2424}
2425
John Kessenich07354242016-07-01 19:58:06 -06002426// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002427// : LEFT_BRACE RIGHT_BRACE
2428// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002429//
2430// initializer_list
2431// : assignment_expression COMMA assignment_expression COMMA ...
2432//
2433bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2434{
2435 // LEFT_BRACE
2436 if (! acceptTokenClass(EHTokLeftBrace))
2437 return false;
2438
John Kessenich98ad4852016-11-27 17:39:07 -07002439 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002440 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002441 if (acceptTokenClass(EHTokRightBrace)) {
2442 // a zero-length initializer list
2443 node = intermediate.makeAggregate(loc);
2444 return true;
2445 }
2446
2447 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002448 node = nullptr;
2449 do {
2450 // assignment_expression
2451 TIntermTyped* expr;
2452 if (! acceptAssignmentExpression(expr)) {
2453 expected("assignment expression in initializer list");
2454 return false;
2455 }
2456 node = intermediate.growAggregate(node, expr, loc);
2457
2458 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002459 if (acceptTokenClass(EHTokComma)) {
2460 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2461 return true;
John Kessenich07354242016-07-01 19:58:06 -06002462 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002463 }
John Kessenich07354242016-07-01 19:58:06 -06002464
2465 // RIGHT_BRACE
2466 if (acceptTokenClass(EHTokRightBrace))
2467 return true;
2468
2469 expected(", or }");
2470 return false;
2471 } while (true);
2472}
2473
John Kessenich34fb0362016-05-03 23:17:20 -06002474// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002475// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002476//
2477// a op (b op (c op d))
2478//
2479// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002480// : initializer
2481// | conditional_expression
2482// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002483//
2484bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2485{
John Kessenich07354242016-07-01 19:58:06 -06002486 // initializer
2487 if (peekTokenClass(EHTokLeftBrace)) {
2488 if (acceptInitializer(node))
2489 return true;
2490
2491 expected("initializer");
2492 return false;
2493 }
2494
John Kessenich00957f82016-07-27 10:39:57 -06002495 // conditional_expression
2496 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002497 return false;
2498
John Kessenich07354242016-07-01 19:58:06 -06002499 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002500 TOperator assignOp = HlslOpMap::assignment(peek());
2501 if (assignOp == EOpNull)
2502 return true;
2503
John Kessenich00957f82016-07-27 10:39:57 -06002504 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002505 TSourceLoc loc = token.loc;
2506 advanceToken();
2507
John Kessenich00957f82016-07-27 10:39:57 -06002508 // conditional_expression assign_op conditional_expression ...
2509 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002510 // gets the right-to-left associativity.
2511 TIntermTyped* rightNode = nullptr;
2512 if (! acceptAssignmentExpression(rightNode)) {
2513 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002514 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002515 }
2516
John Kessenichd21baed2016-09-16 03:05:12 -06002517 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002518 node = parseContext.handleLvalue(loc, "assign", node);
2519
John Kessenichfea226b2016-07-28 17:53:56 -06002520 if (node == nullptr) {
2521 parseContext.error(loc, "could not create assignment", "", "");
2522 return false;
2523 }
John Kessenich34fb0362016-05-03 23:17:20 -06002524
2525 if (! peekTokenClass(EHTokComma))
2526 return true;
2527
2528 return true;
2529}
2530
John Kessenich00957f82016-07-27 10:39:57 -06002531// Accept a conditional expression, which associates right-to-left,
2532// accomplished by the "true" expression calling down to lower
2533// precedence levels than this level.
2534//
2535// conditional_expression
2536// : binary_expression
2537// | binary_expression QUESTION expression COLON assignment_expression
2538//
2539bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2540{
2541 // binary_expression
2542 if (! acceptBinaryExpression(node, PlLogicalOr))
2543 return false;
2544
2545 if (! acceptTokenClass(EHTokQuestion))
2546 return true;
2547
John Kessenich636b62d2017-04-11 19:45:00 -06002548 node = parseContext.convertConditionalExpression(token.loc, node, false);
John Kessenich7e997e22017-03-30 22:09:30 -06002549 if (node == nullptr)
2550 return false;
2551
John Kessenich00957f82016-07-27 10:39:57 -06002552 TIntermTyped* trueNode = nullptr;
2553 if (! acceptExpression(trueNode)) {
2554 expected("expression after ?");
2555 return false;
2556 }
2557 TSourceLoc loc = token.loc;
2558
2559 if (! acceptTokenClass(EHTokColon)) {
2560 expected(":");
2561 return false;
2562 }
2563
2564 TIntermTyped* falseNode = nullptr;
2565 if (! acceptAssignmentExpression(falseNode)) {
2566 expected("expression after :");
2567 return false;
2568 }
2569
2570 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2571
2572 return true;
2573}
2574
John Kessenich34fb0362016-05-03 23:17:20 -06002575// Accept a binary expression, for binary operations that
2576// associate left-to-right. This is, it is implicit, for example
2577//
2578// ((a op b) op c) op d
2579//
2580// binary_expression
2581// : expression op expression op expression ...
2582//
2583// where 'expression' is the next higher level in precedence.
2584//
2585bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2586{
2587 if (precedenceLevel > PlMul)
2588 return acceptUnaryExpression(node);
2589
2590 // assignment_expression
2591 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2592 return false;
2593
John Kessenich34fb0362016-05-03 23:17:20 -06002594 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002595 TOperator op = HlslOpMap::binary(peek());
2596 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2597 if (tokenLevel < precedenceLevel)
2598 return true;
2599
John Kessenich34fb0362016-05-03 23:17:20 -06002600 // ... op
2601 TSourceLoc loc = token.loc;
2602 advanceToken();
2603
2604 // ... expression
2605 TIntermTyped* rightNode = nullptr;
2606 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2607 expected("expression");
2608 return false;
2609 }
2610
2611 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002612 if (node == nullptr) {
2613 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2614 return false;
2615 }
John Kessenich34fb0362016-05-03 23:17:20 -06002616 } while (true);
2617}
2618
2619// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002620// : (type) unary_expression
2621// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002622// | - unary_expression
2623// | ! unary_expression
2624// | ~ unary_expression
2625// | ++ unary_expression
2626// | -- unary_expression
2627// | postfix_expression
2628//
2629bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2630{
John Kessenich1cc1a282016-06-03 16:55:49 -06002631 // (type) unary_expression
2632 // Have to look two steps ahead, because this could be, e.g., a
2633 // postfix_expression instead, since that also starts with at "(".
2634 if (acceptTokenClass(EHTokLeftParen)) {
2635 TType castType;
2636 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002637 if (acceptTokenClass(EHTokRightParen)) {
2638 // We've matched "(type)" now, get the expression to cast
2639 TSourceLoc loc = token.loc;
2640 if (! acceptUnaryExpression(node))
2641 return false;
2642
2643 // Hook it up like a constructor
John Kessenichc633f642017-04-03 21:48:37 -06002644 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
steve-lunarg5964c642016-07-30 07:38:55 -06002645 if (constructorFunction == nullptr) {
2646 expected("type that can be constructed");
2647 return false;
2648 }
2649 TIntermTyped* arguments = nullptr;
2650 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2651 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2652
2653 return true;
2654 } else {
2655 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2656 // the '(int' part. We must back up twice.
2657 recedeToken();
2658 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002659 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002660 } else {
2661 // This isn't a type cast, but it still started "(", so if it is a
2662 // unary expression, it can only be a postfix_expression, so try that.
2663 // Back it up first.
2664 recedeToken();
2665 return acceptPostfixExpression(node);
2666 }
2667 }
2668
2669 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002670 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002671
John Kessenich1cc1a282016-06-03 16:55:49 -06002672 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002673 if (unaryOp == EOpNull)
2674 return acceptPostfixExpression(node);
2675
2676 // op unary_expression
2677 TSourceLoc loc = token.loc;
2678 advanceToken();
2679 if (! acceptUnaryExpression(node))
2680 return false;
2681
2682 // + is a no-op
2683 if (unaryOp == EOpAdd)
2684 return true;
2685
2686 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002687
2688 // These unary ops require lvalues
2689 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2690 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002691
2692 return node != nullptr;
2693}
2694
2695// postfix_expression
2696// : LEFT_PAREN expression RIGHT_PAREN
2697// | literal
2698// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002699// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002700// | function_call
2701// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2702// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002703// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002704// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002705// | postfix_expression INC_OP
2706// | postfix_expression DEC_OP
2707//
2708bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2709{
2710 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002711 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002712
2713 // idToken will pick up either a variable or a function name in a function call
2714 HlslToken idToken;
2715
John Kessenich21472ae2016-06-04 11:46:33 -06002716 // Find something before the postfix operations, as they can't operate
2717 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002718 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002719 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002720 if (! acceptExpression(node)) {
2721 expected("expression");
2722 return false;
2723 }
2724 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002725 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002726 return false;
2727 }
John Kessenich34fb0362016-05-03 23:17:20 -06002728 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002729 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002730 } else if (acceptConstructor(node)) {
2731 // constructor (nothing else to do yet)
2732 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002733 // user-type, namespace name, variable, or function name
2734 TString* fullName = idToken.string;
2735 while (acceptTokenClass(EHTokColonColon)) {
2736 // user-type or namespace name
2737 fullName = NewPoolTString(fullName->c_str());
2738 fullName->append(parseContext.scopeMangler);
2739 if (acceptIdentifier(idToken))
2740 fullName->append(*idToken.string);
2741 else {
2742 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002743 return false;
2744 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002745 }
2746 if (! peekTokenClass(EHTokLeftParen)) {
2747 node = parseContext.handleVariable(idToken.loc, fullName);
2748 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002749 // function_call (nothing else to do yet)
2750 } else {
2751 expected("function call arguments");
2752 return false;
2753 }
John Kessenich21472ae2016-06-04 11:46:33 -06002754 } else {
2755 // nothing found, can't post operate
2756 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002757 }
2758
steve-lunarga2b01a02016-11-28 17:09:54 -07002759 // This is to guarantee we do this no matter how we get out of the stack frame.
2760 // This way there's no bug if an early return forgets to do it.
2761 struct tFinalize {
2762 tFinalize(HlslParseContext& p) : parseContext(p) { }
2763 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002764 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002765 private:
John Kessenichca71d942017-03-07 20:44:09 -07002766 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002767 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002768 } finalize(parseContext);
2769
2770 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2771 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2772 // level: hence the init and finalize. Even though in practice these must be
2773 // constants, they are parsed no matter what.
2774 parseContext.initFlattening();
2775
John Kessenich21472ae2016-06-04 11:46:33 -06002776 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002777 do {
2778 TSourceLoc loc = token.loc;
2779 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002780
John Kessenich34fb0362016-05-03 23:17:20 -06002781 // Consume only a valid post-unary operator, otherwise we are done.
2782 switch (postOp) {
2783 case EOpIndexDirectStruct:
2784 case EOpIndexIndirect:
2785 case EOpPostIncrement:
2786 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002787 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002788 advanceToken();
2789 break;
2790 default:
2791 return true;
2792 }
John Kessenich87142c72016-03-12 20:24:24 -07002793
John Kessenich34fb0362016-05-03 23:17:20 -06002794 // We have a valid post-unary operator, process it.
2795 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002796 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002797 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002798 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002799 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002800 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002801 HlslToken field;
2802 if (! acceptIdentifier(field)) {
2803 expected("swizzle or member");
2804 return false;
2805 }
LoopDawg4886f692016-06-29 10:58:58 -06002806
John Kessenich516d92d2017-03-08 20:09:03 -07002807 if (peekTokenClass(EHTokLeftParen)) {
2808 // member function
2809 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002810
John Kessenich516d92d2017-03-08 20:09:03 -07002811 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002812 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002813 expected("function parameters");
2814 return false;
2815 }
John Kessenich516d92d2017-03-08 20:09:03 -07002816 } else
2817 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002818
John Kessenich34fb0362016-05-03 23:17:20 -06002819 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002820 }
John Kessenich34fb0362016-05-03 23:17:20 -06002821 case EOpIndexIndirect:
2822 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002823 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002824 TIntermTyped* indexNode = nullptr;
2825 if (! acceptExpression(indexNode) ||
2826 ! peekTokenClass(EHTokRightBracket)) {
2827 expected("expression followed by ']'");
2828 return false;
2829 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002830 advanceToken();
2831 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
steve-lunarg2efd6c62017-04-06 20:22:20 -06002832 if (node == nullptr)
2833 return false;
John Kessenich19b92ff2016-06-19 11:50:34 -06002834 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002835 }
2836 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002837 // INC_OP
2838 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002839 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002840 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002841 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002842 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002843 break;
2844 default:
2845 assert(0);
2846 break;
2847 }
2848 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002849}
2850
John Kessenichd016be12016-03-13 11:24:20 -06002851// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002852// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002853//
2854bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2855{
2856 // type
2857 TType type;
2858 if (acceptType(type)) {
John Kessenichc633f642017-04-03 21:48:37 -06002859 TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
John Kessenichd016be12016-03-13 11:24:20 -06002860 if (constructorFunction == nullptr)
2861 return false;
2862
2863 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002864 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002865 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002866 // It's possible this is a type keyword used as an identifier. Put the token back
2867 // for later use.
2868 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002869 return false;
2870 }
2871
2872 // hook it up
2873 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2874
2875 return true;
2876 }
2877
2878 return false;
2879}
2880
John Kessenich34fb0362016-05-03 23:17:20 -06002881// The function_call identifier was already recognized, and passed in as idToken.
2882//
2883// function_call
2884// : [idToken] arguments
2885//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002886bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002887{
John Kessenich54ee28f2017-03-11 14:13:00 -07002888 // name
2889 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002890 if (baseObject == nullptr) {
2891 functionName = &name;
2892 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002893 // Built-in methods are not in the symbol table as methods, but as global functions
2894 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002895 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002896 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002897 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002898 if (! baseObject->getType().isStruct()) {
2899 expected("structure");
2900 return false;
2901 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002902 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002903 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002904 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002905 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002906 }
LoopDawg4886f692016-06-29 10:58:58 -06002907
John Kessenich54ee28f2017-03-11 14:13:00 -07002908 // function
2909 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2910
2911 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002912 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002913 if (baseObject != nullptr) {
2914 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002915 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002916 }
John Kessenich4678ca92016-05-13 09:33:42 -06002917 if (! acceptArguments(function, arguments))
2918 return false;
2919
John Kessenich54ee28f2017-03-11 14:13:00 -07002920 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002921 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002922
2923 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002924}
2925
John Kessenich87142c72016-03-12 20:24:24 -07002926// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002927// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002928//
John Kessenichd016be12016-03-13 11:24:20 -06002929// The arguments are pushed onto the 'function' argument list and
2930// onto the 'arguments' aggregate.
2931//
John Kessenich4678ca92016-05-13 09:33:42 -06002932bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002933{
John Kessenich078d7f22016-03-14 10:02:11 -06002934 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002935 if (! acceptTokenClass(EHTokLeftParen))
2936 return false;
2937
John Kessenich2aa12b12017-04-18 14:47:33 -06002938 // RIGHT_PAREN
2939 if (acceptTokenClass(EHTokRightParen))
2940 return true;
2941
2942 // must now be at least one expression...
John Kessenich87142c72016-03-12 20:24:24 -07002943 do {
John Kessenichd016be12016-03-13 11:24:20 -06002944 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002945 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002946 if (! acceptAssignmentExpression(arg))
John Kessenich2aa12b12017-04-18 14:47:33 -06002947 return false;
John Kessenichd016be12016-03-13 11:24:20 -06002948
2949 // hook it up
2950 parseContext.handleFunctionArgument(function, arguments, arg);
2951
John Kessenich078d7f22016-03-14 10:02:11 -06002952 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002953 if (! acceptTokenClass(EHTokComma))
2954 break;
2955 } while (true);
2956
John Kessenich078d7f22016-03-14 10:02:11 -06002957 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002958 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002959 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002960 return false;
2961 }
2962
2963 return true;
2964}
2965
2966bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2967{
2968 switch (token.tokenClass) {
2969 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002970 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002971 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002972 case EHTokUintConstant:
2973 node = intermediate.addConstantUnion(token.u, token.loc, true);
2974 break;
John Kessenich87142c72016-03-12 20:24:24 -07002975 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002976 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002977 break;
2978 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002979 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002980 break;
2981 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002982 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002983 break;
John Kessenich86f71382016-09-19 20:23:18 -06002984 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002985 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002986 break;
John Kessenich87142c72016-03-12 20:24:24 -07002987
2988 default:
2989 return false;
2990 }
2991
2992 advanceToken();
2993
2994 return true;
2995}
2996
John Kessenich5f934b02016-03-13 17:58:25 -06002997// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002998// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002999//
John Kessenich21472ae2016-06-04 11:46:33 -06003000bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07003001{
John Kessenich21472ae2016-06-04 11:46:33 -06003002 TIntermAggregate* compoundStatement = nullptr;
3003
John Kessenich34fb0362016-05-03 23:17:20 -06003004 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003005 if (! acceptTokenClass(EHTokLeftBrace))
3006 return false;
3007
3008 // statement statement ...
3009 TIntermNode* statement = nullptr;
3010 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06003011 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
3012 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
3013 branch->getFlowOp() == EOpDefault)) {
3014 // hook up individual subsequences within a switch statement
3015 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
3016 compoundStatement = nullptr;
3017 } else {
3018 // hook it up to the growing compound statement
3019 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3020 }
John Kessenich5f934b02016-03-13 17:58:25 -06003021 }
John Kessenich34fb0362016-05-03 23:17:20 -06003022 if (compoundStatement)
3023 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06003024
John Kessenich21472ae2016-06-04 11:46:33 -06003025 retStatement = compoundStatement;
3026
John Kessenich34fb0362016-05-03 23:17:20 -06003027 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003028 return acceptTokenClass(EHTokRightBrace);
3029}
3030
John Kessenich0d2b6de2016-06-05 11:23:11 -06003031bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3032{
3033 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003034 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003035 parseContext.popScope();
3036
3037 return result;
3038}
3039
John Kessenich077e0522016-06-09 02:02:17 -06003040bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003041{
John Kessenich077e0522016-06-09 02:02:17 -06003042 parseContext.pushScope();
3043 bool result = acceptCompoundStatement(statement);
3044 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003045
3046 return result;
3047}
3048
John Kessenich5f934b02016-03-13 17:58:25 -06003049// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003050// : attributes attributed_statement
3051//
3052// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003053// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003054// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06003055// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06003056// | declaration_statement
3057// | selection_statement
3058// | switch_statement
3059// | case_label
3060// | iteration_statement
3061// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003062//
3063bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3064{
John Kessenich21472ae2016-06-04 11:46:33 -06003065 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003066
John Kessenich21472ae2016-06-04 11:46:33 -06003067 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003068 TAttributeMap attributes;
3069 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003070
John Kessenich21472ae2016-06-04 11:46:33 -06003071 // attributed_statement
3072 switch (peek()) {
3073 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003074 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003075
John Kessenich21472ae2016-06-04 11:46:33 -06003076 case EHTokIf:
3077 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003078
John Kessenich21472ae2016-06-04 11:46:33 -06003079 case EHTokSwitch:
3080 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003081
John Kessenich21472ae2016-06-04 11:46:33 -06003082 case EHTokFor:
3083 case EHTokDo:
3084 case EHTokWhile:
3085 return acceptIterationStatement(statement);
3086
3087 case EHTokContinue:
3088 case EHTokBreak:
3089 case EHTokDiscard:
3090 case EHTokReturn:
3091 return acceptJumpStatement(statement);
3092
3093 case EHTokCase:
3094 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003095 case EHTokDefault:
3096 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003097
3098 case EHTokSemicolon:
3099 return acceptTokenClass(EHTokSemicolon);
3100
3101 case EHTokRightBrace:
3102 // Performance: not strictly necessary, but stops a bunch of hunting early,
3103 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003104 return false;
3105
John Kessenich21472ae2016-06-04 11:46:33 -06003106 default:
3107 {
3108 // declaration
3109 if (acceptDeclaration(statement))
3110 return true;
3111
3112 // expression
3113 TIntermTyped* node;
3114 if (acceptExpression(node))
3115 statement = node;
3116 else
3117 return false;
3118
3119 // SEMICOLON (following an expression)
3120 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003121 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003122 return false;
3123 }
3124 }
3125 }
3126
John Kessenich5f934b02016-03-13 17:58:25 -06003127 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003128}
3129
John Kessenich21472ae2016-06-04 11:46:33 -06003130// attributes
3131// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3132//
3133// attribute:
3134// : UNROLL
3135// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3136// | FASTOPT
3137// | ALLOW_UAV_CONDITION
3138// | BRANCH
3139// | FLATTEN
3140// | FORCECASE
3141// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003142// | DOMAIN
3143// | EARLYDEPTHSTENCIL
3144// | INSTANCE
3145// | MAXTESSFACTOR
3146// | OUTPUTCONTROLPOINTS
3147// | OUTPUTTOPOLOGY
3148// | PARTITIONING
3149// | PATCHCONSTANTFUNC
3150// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003151//
steve-lunarg1868b142016-10-20 13:07:10 -06003152void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003153{
steve-lunarg1868b142016-10-20 13:07:10 -06003154 // For now, accept the [ XXX(X) ] syntax, but drop all but
3155 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003156 // TODO: subset to correct set? Pass on?
3157 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003158 HlslToken idToken;
3159
John Kessenich0d2b6de2016-06-05 11:23:11 -06003160 // LEFT_BRACKET?
3161 if (! acceptTokenClass(EHTokLeftBracket))
3162 return;
3163
3164 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003165 if (acceptIdentifier(idToken)) {
3166 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003167 } else if (! peekTokenClass(EHTokRightBracket)) {
3168 expected("identifier");
3169 advanceToken();
3170 }
3171
steve-lunarga22f7db2016-11-11 08:17:44 -07003172 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003173
3174 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003175 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003176 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003177
John Kessenich0d2b6de2016-06-05 11:23:11 -06003178 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003179 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003180
steve-lunarga22f7db2016-11-11 08:17:44 -07003181 while (acceptAssignmentExpression(node)) {
3182 expectingExpression = false;
3183 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003184 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003185 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003186 }
3187
steve-lunarga22f7db2016-11-11 08:17:44 -07003188 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003189 if (! acceptTokenClass(EHTokRightParen))
3190 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003191
3192 // Error for partial or missing expression
3193 if (expectingExpression || expressions->getSequence().empty())
3194 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003195 }
3196
3197 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003198 if (!acceptTokenClass(EHTokRightBracket)) {
3199 expected("]");
3200 return;
3201 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003202
steve-lunarg1868b142016-10-20 13:07:10 -06003203 // Add any values we found into the attribute map. This accepts
3204 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003205 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003206 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003207}
3208
John Kessenich0d2b6de2016-06-05 11:23:11 -06003209// selection_statement
3210// : IF LEFT_PAREN expression RIGHT_PAREN statement
3211// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3212//
John Kessenich21472ae2016-06-04 11:46:33 -06003213bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3214{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003215 TSourceLoc loc = token.loc;
3216
3217 // IF
3218 if (! acceptTokenClass(EHTokIf))
3219 return false;
3220
3221 // so that something declared in the condition is scoped to the lifetimes
3222 // of the then-else statements
3223 parseContext.pushScope();
3224
3225 // LEFT_PAREN expression RIGHT_PAREN
3226 TIntermTyped* condition;
3227 if (! acceptParenExpression(condition))
3228 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003229 condition = parseContext.convertConditionalExpression(loc, condition);
3230 if (condition == nullptr)
3231 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003232
3233 // create the child statements
3234 TIntermNodePair thenElse = { nullptr, nullptr };
3235
3236 // then statement
3237 if (! acceptScopedStatement(thenElse.node1)) {
3238 expected("then statement");
3239 return false;
3240 }
3241
3242 // ELSE
3243 if (acceptTokenClass(EHTokElse)) {
3244 // else statement
3245 if (! acceptScopedStatement(thenElse.node2)) {
3246 expected("else statement");
3247 return false;
3248 }
3249 }
3250
3251 // Put the pieces together
3252 statement = intermediate.addSelection(condition, thenElse, loc);
3253 parseContext.popScope();
3254
3255 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003256}
3257
John Kessenichd02dc5d2016-07-01 00:04:11 -06003258// switch_statement
3259// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3260//
John Kessenich21472ae2016-06-04 11:46:33 -06003261bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3262{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003263 // SWITCH
3264 TSourceLoc loc = token.loc;
3265 if (! acceptTokenClass(EHTokSwitch))
3266 return false;
3267
3268 // LEFT_PAREN expression RIGHT_PAREN
3269 parseContext.pushScope();
3270 TIntermTyped* switchExpression;
3271 if (! acceptParenExpression(switchExpression)) {
3272 parseContext.popScope();
3273 return false;
3274 }
3275
3276 // compound_statement
3277 parseContext.pushSwitchSequence(new TIntermSequence);
3278 bool statementOkay = acceptCompoundStatement(statement);
3279 if (statementOkay)
3280 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3281
3282 parseContext.popSwitchSequence();
3283 parseContext.popScope();
3284
3285 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003286}
3287
John Kessenich119f8f62016-06-05 15:44:07 -06003288// iteration_statement
3289// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3290// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3291// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3292//
3293// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003294bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3295{
John Kessenich119f8f62016-06-05 15:44:07 -06003296 TSourceLoc loc = token.loc;
3297 TIntermTyped* condition = nullptr;
3298
3299 EHlslTokenClass loop = peek();
3300 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3301
3302 // WHILE or DO or FOR
3303 advanceToken();
3304
3305 switch (loop) {
3306 case EHTokWhile:
3307 // so that something declared in the condition is scoped to the lifetime
3308 // of the while sub-statement
3309 parseContext.pushScope();
3310 parseContext.nestLooping();
3311
3312 // LEFT_PAREN condition RIGHT_PAREN
3313 if (! acceptParenExpression(condition))
3314 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003315 condition = parseContext.convertConditionalExpression(loc, condition);
3316 if (condition == nullptr)
3317 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003318
3319 // statement
3320 if (! acceptScopedStatement(statement)) {
3321 expected("while sub-statement");
3322 return false;
3323 }
3324
3325 parseContext.unnestLooping();
3326 parseContext.popScope();
3327
3328 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3329
3330 return true;
3331
3332 case EHTokDo:
3333 parseContext.nestLooping();
3334
John Kessenich119f8f62016-06-05 15:44:07 -06003335 // statement
John Kessenich0c6f9362017-04-20 11:08:24 -06003336 if (! acceptScopedStatement(statement)) {
John Kessenich119f8f62016-06-05 15:44:07 -06003337 expected("do sub-statement");
3338 return false;
3339 }
3340
John Kessenich119f8f62016-06-05 15:44:07 -06003341 // WHILE
3342 if (! acceptTokenClass(EHTokWhile)) {
3343 expected("while");
3344 return false;
3345 }
3346
3347 // LEFT_PAREN condition RIGHT_PAREN
3348 TIntermTyped* condition;
3349 if (! acceptParenExpression(condition))
3350 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003351 condition = parseContext.convertConditionalExpression(loc, condition);
3352 if (condition == nullptr)
3353 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003354
3355 if (! acceptTokenClass(EHTokSemicolon))
3356 expected(";");
3357
3358 parseContext.unnestLooping();
3359
3360 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3361
3362 return true;
3363
3364 case EHTokFor:
3365 {
3366 // LEFT_PAREN
3367 if (! acceptTokenClass(EHTokLeftParen))
3368 expected("(");
3369
3370 // so that something declared in the condition is scoped to the lifetime
3371 // of the for sub-statement
3372 parseContext.pushScope();
3373
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003374 // initializer
3375 TIntermNode* initNode = nullptr;
3376 if (! acceptControlDeclaration(initNode)) {
3377 TIntermTyped* initExpr = nullptr;
3378 acceptExpression(initExpr);
3379 initNode = initExpr;
3380 }
3381 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003382 if (! acceptTokenClass(EHTokSemicolon))
3383 expected(";");
3384
3385 parseContext.nestLooping();
3386
3387 // condition SEMI_COLON
3388 acceptExpression(condition);
3389 if (! acceptTokenClass(EHTokSemicolon))
3390 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003391 if (condition != nullptr) {
3392 condition = parseContext.convertConditionalExpression(loc, condition);
3393 if (condition == nullptr)
3394 return false;
3395 }
John Kessenich119f8f62016-06-05 15:44:07 -06003396
3397 // iterator SEMI_COLON
3398 TIntermTyped* iterator = nullptr;
3399 acceptExpression(iterator);
3400 if (! acceptTokenClass(EHTokRightParen))
3401 expected(")");
3402
3403 // statement
3404 if (! acceptScopedStatement(statement)) {
3405 expected("for sub-statement");
3406 return false;
3407 }
3408
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003409 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003410
3411 parseContext.popScope();
3412 parseContext.unnestLooping();
3413
3414 return true;
3415 }
3416
3417 default:
3418 return false;
3419 }
John Kessenich21472ae2016-06-04 11:46:33 -06003420}
3421
3422// jump_statement
3423// : CONTINUE SEMICOLON
3424// | BREAK SEMICOLON
3425// | DISCARD SEMICOLON
3426// | RETURN SEMICOLON
3427// | RETURN expression SEMICOLON
3428//
3429bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3430{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003431 EHlslTokenClass jump = peek();
3432 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003433 case EHTokContinue:
3434 case EHTokBreak:
3435 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003436 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003437 advanceToken();
3438 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003439 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003440 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003441 return false;
3442 }
John Kessenich21472ae2016-06-04 11:46:33 -06003443
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003444 switch (jump) {
3445 case EHTokContinue:
3446 statement = intermediate.addBranch(EOpContinue, token.loc);
3447 break;
3448 case EHTokBreak:
3449 statement = intermediate.addBranch(EOpBreak, token.loc);
3450 break;
3451 case EHTokDiscard:
3452 statement = intermediate.addBranch(EOpKill, token.loc);
3453 break;
3454
3455 case EHTokReturn:
3456 {
3457 // expression
3458 TIntermTyped* node;
3459 if (acceptExpression(node)) {
3460 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003461 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003462 } else
3463 statement = intermediate.addBranch(EOpReturn, token.loc);
3464 break;
3465 }
3466
3467 default:
3468 assert(0);
3469 return false;
3470 }
3471
3472 // SEMICOLON
3473 if (! acceptTokenClass(EHTokSemicolon))
3474 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003475
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003476 return true;
3477}
John Kessenich21472ae2016-06-04 11:46:33 -06003478
John Kessenichd02dc5d2016-07-01 00:04:11 -06003479// case_label
3480// : CASE expression COLON
3481//
John Kessenich21472ae2016-06-04 11:46:33 -06003482bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3483{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003484 TSourceLoc loc = token.loc;
3485 if (! acceptTokenClass(EHTokCase))
3486 return false;
3487
3488 TIntermTyped* expression;
3489 if (! acceptExpression(expression)) {
3490 expected("case expression");
3491 return false;
3492 }
3493
3494 if (! acceptTokenClass(EHTokColon)) {
3495 expected(":");
3496 return false;
3497 }
3498
3499 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3500
3501 return true;
3502}
3503
3504// default_label
3505// : DEFAULT COLON
3506//
3507bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3508{
3509 TSourceLoc loc = token.loc;
3510 if (! acceptTokenClass(EHTokDefault))
3511 return false;
3512
3513 if (! acceptTokenClass(EHTokColon)) {
3514 expected(":");
3515 return false;
3516 }
3517
3518 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3519
3520 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003521}
3522
John Kessenich19b92ff2016-06-19 11:50:34 -06003523// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003524// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3525// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003526//
3527void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3528{
3529 arraySizes = nullptr;
3530
steve-lunarg7b211a32016-10-13 12:26:18 -06003531 // Early-out if there aren't any array dimensions
3532 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003533 return;
3534
steve-lunarg7b211a32016-10-13 12:26:18 -06003535 // 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 -06003536 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003537
3538 // Collect each array dimension.
3539 while (acceptTokenClass(EHTokLeftBracket)) {
3540 TSourceLoc loc = token.loc;
3541 TIntermTyped* sizeExpr = nullptr;
3542
John Kessenich057df292017-03-06 18:18:37 -07003543 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003544 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3545
3546 if (! acceptTokenClass(EHTokRightBracket)) {
3547 expected("]");
3548 return;
3549 }
3550
3551 if (hasArraySize) {
3552 TArraySize arraySize;
3553 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3554 arraySizes->addInnerSize(arraySize);
3555 } else {
3556 arraySizes->addInnerSize(0); // sized by initializers.
3557 }
steve-lunarg265c0612016-09-27 10:57:35 -06003558 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003559}
3560
John Kessenich630dd7d2016-06-12 23:52:12 -06003561// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003562// : COLON semantic // optional
3563// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3564// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003565// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003566// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003567//
John Kessenich854fe242017-03-02 14:30:59 -07003568// Return true if any tokens were accepted. That is,
3569// false can be returned on successfully recognizing nothing,
3570// not necessarily meaning bad syntax.
3571//
3572bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003573{
John Kessenich854fe242017-03-02 14:30:59 -07003574 bool found = false;
3575
John Kessenich630dd7d2016-06-12 23:52:12 -06003576 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003577 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003578 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003579 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003580 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003581 if (peekTokenClass(EHTokLayout))
3582 acceptLayoutQualifierList(qualifier);
3583 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003584 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003585 if (! acceptTokenClass(EHTokLeftParen)) {
3586 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003587 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003588 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003589 HlslToken locationToken;
3590 if (! acceptIdentifier(locationToken)) {
3591 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003592 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003593 }
3594 HlslToken componentToken;
3595 if (acceptTokenClass(EHTokDot)) {
3596 if (! acceptIdentifier(componentToken)) {
3597 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003598 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003599 }
3600 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003601 if (! acceptTokenClass(EHTokRightParen)) {
3602 expected(")");
3603 break;
3604 }
John Kessenich7735b942016-09-05 12:40:06 -06003605 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003606 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003607 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003608 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003609 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003610 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3611 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003612 if (! acceptTokenClass(EHTokLeftParen)) {
3613 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003614 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003615 }
John Kessenichb38f0712016-07-30 10:29:54 -06003616 HlslToken registerDesc; // for Type#
3617 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003618 if (! acceptIdentifier(registerDesc)) {
3619 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003620 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003621 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003622 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3623 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003624 // Then we didn't really see the registerDesc yet, it was
3625 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003626 profile = registerDesc;
3627 if (! acceptIdentifier(registerDesc)) {
3628 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003629 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003630 }
3631 }
John Kessenichb38f0712016-07-30 10:29:54 -06003632 int subComponent = 0;
3633 if (acceptTokenClass(EHTokLeftBracket)) {
3634 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3635 if (! peekTokenClass(EHTokIntConstant)) {
3636 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003637 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003638 }
3639 subComponent = token.i;
3640 advanceToken();
3641 if (! acceptTokenClass(EHTokRightBracket)) {
3642 expected("]");
3643 break;
3644 }
3645 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003646 // (COMMA SPACEN)opt
3647 HlslToken spaceDesc;
3648 if (acceptTokenClass(EHTokComma)) {
3649 if (! acceptIdentifier(spaceDesc)) {
3650 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003651 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003652 }
3653 }
3654 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003655 if (! acceptTokenClass(EHTokRightParen)) {
3656 expected(")");
3657 break;
3658 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003659 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003660 } else {
3661 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003662 TString semanticUpperCase = *idToken.string;
3663 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3664 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003665 }
John Kessenich854fe242017-03-02 14:30:59 -07003666 } else if (peekTokenClass(EHTokLeftAngle)) {
3667 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003668 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003669 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003670 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003671
John Kessenich630dd7d2016-06-12 23:52:12 -06003672 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003673
3674 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003675}
3676
John Kessenichb16f7e62017-03-11 19:32:47 -07003677//
3678// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3679// processing.
3680//
3681bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3682{
3683 if (! peekTokenClass(EHTokLeftBrace))
3684 return false;
3685
3686 int braceCount = 0;
3687
3688 do {
3689 switch (peek()) {
3690 case EHTokLeftBrace:
3691 ++braceCount;
3692 break;
3693 case EHTokRightBrace:
3694 --braceCount;
3695 break;
3696 case EHTokNone:
3697 // End of input before balance { } is bad...
3698 return false;
3699 default:
3700 break;
3701 }
3702
3703 tokens.push_back(token);
3704 advanceToken();
3705 } while (braceCount > 0);
3706
3707 return true;
3708}
3709
John Kesseniche01a9bc2016-03-12 20:11:22 -07003710} // end namespace glslang