blob: aab3cb141c7834a5756b43d025cad0a07fe194f6 [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
John Kessenich0320d092017-06-13 22:22:52 -0600110 const char* idString = getTypeString(peek());
111 if (idString == nullptr)
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700112 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700113
John Kessenich0320d092017-06-13 22:22:52 -0600114 token.string = NewPoolTString(idString);
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700115 token.tokenClass = EHTokIdentifier;
John Kessenich0320d092017-06-13 22:22:52 -0600116 idToken = token;
117 typeIdentifiers = true;
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700118
119 advanceToken();
120
121 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600122}
123
John Kesseniche01a9bc2016-03-12 20:11:22 -0700124// compilationUnit
John Kessenich8f9fdc92017-03-30 16:22:26 -0600125// : declaration_list EOF
John Kesseniche01a9bc2016-03-12 20:11:22 -0700126//
127bool HlslGrammar::acceptCompilationUnit()
128{
John Kessenichd016be12016-03-13 11:24:20 -0600129 TIntermNode* unitNode = nullptr;
130
John Kessenich8f9fdc92017-03-30 16:22:26 -0600131 if (! acceptDeclarationList(unitNode))
132 return false;
steve-lunargcb88de52016-08-03 07:04:18 -0600133
John Kessenich8f9fdc92017-03-30 16:22:26 -0600134 if (! peekTokenClass(EHTokNone))
135 return false;
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136
John Kessenichd016be12016-03-13 11:24:20 -0600137 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700138 if (unitNode && !unitNode->getAsAggregate())
139 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600140 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600141
John Kesseniche01a9bc2016-03-12 20:11:22 -0700142 return true;
143}
144
John Kessenich8f9fdc92017-03-30 16:22:26 -0600145// Recognize the following, but with the extra condition that it can be
146// successfully terminated by EOF or '}'.
147//
148// declaration_list
149// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
150//
151// declaration_or_semicolon
152// : declaration
153// : SEMICOLON
154//
155bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
156{
157 do {
158 // HLSL allows extra semicolons between global declarations
159 do { } while (acceptTokenClass(EHTokSemicolon));
160
161 // EOF or RIGHT_BRACE
162 if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
163 return true;
164
165 // declaration
166 if (! acceptDeclaration(nodeList))
167 return false;
168 } while (true);
169
170 return true;
171}
172
LoopDawg4886f692016-06-29 10:58:58 -0600173// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700174// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600175//
176// sampler_state_assignment
177// : sampler_state_identifier EQUAL value SEMICOLON
178//
179// sampler_state_identifier
180// : ADDRESSU
181// | ADDRESSV
182// | ADDRESSW
183// | BORDERCOLOR
184// | FILTER
185// | MAXANISOTROPY
186// | MAXLOD
187// | MINLOD
188// | MIPLODBIAS
189//
190bool HlslGrammar::acceptSamplerState()
191{
192 // TODO: this should be genericized to accept a list of valid tokens and
193 // return token/value pairs. Presently it is specific to texture values.
194
195 if (! acceptTokenClass(EHTokLeftBrace))
196 return true;
197
198 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700199
LoopDawg4886f692016-06-29 10:58:58 -0600200 do {
201 // read state name
202 HlslToken state;
203 if (! acceptIdentifier(state))
204 break; // end of list
205
206 // FXC accepts any case
207 TString stateName = *state.string;
208 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
209
210 if (! acceptTokenClass(EHTokAssign)) {
211 expected("assign");
212 return false;
213 }
214
215 if (stateName == "minlod" || stateName == "maxlod") {
216 if (! peekTokenClass(EHTokIntConstant)) {
217 expected("integer");
218 return false;
219 }
220
221 TIntermTyped* lod = nullptr;
222 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
223 return false;
224 } else if (stateName == "maxanisotropy") {
225 if (! peekTokenClass(EHTokIntConstant)) {
226 expected("integer");
227 return false;
228 }
229
230 TIntermTyped* maxAnisotropy = nullptr;
231 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
232 return false;
233 } else if (stateName == "filter") {
234 HlslToken filterMode;
235 if (! acceptIdentifier(filterMode)) {
236 expected("filter mode");
237 return false;
238 }
239 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
240 HlslToken addrMode;
241 if (! acceptIdentifier(addrMode)) {
242 expected("texture address mode");
243 return false;
244 }
245 } else if (stateName == "miplodbias") {
246 TIntermTyped* lodBias = nullptr;
247 if (! acceptLiteral(lodBias)) {
248 expected("lod bias");
249 return false;
250 }
251 } else if (stateName == "bordercolor") {
252 return false;
253 } else {
254 expected("texture state");
255 return false;
256 }
257
258 // SEMICOLON
259 if (! acceptTokenClass(EHTokSemicolon)) {
260 expected("semicolon");
261 return false;
262 }
263 } while (true);
264
265 if (! acceptTokenClass(EHTokRightBrace))
266 return false;
267
268 return true;
269}
270
271// sampler_declaration_dx9
272// : SAMPLER identifier EQUAL sampler_type sampler_state
273//
John Kesseniche4821e42016-07-16 10:19:43 -0600274bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600275{
276 if (! acceptTokenClass(EHTokSampler))
277 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700278
LoopDawg4886f692016-06-29 10:58:58 -0600279 // TODO: remove this when DX9 style declarations are implemented.
280 unimplemented("Direct3D 9 sampler declaration");
281
282 // read sampler name
283 HlslToken name;
284 if (! acceptIdentifier(name)) {
285 expected("sampler name");
286 return false;
287 }
288
289 if (! acceptTokenClass(EHTokAssign)) {
290 expected("=");
291 return false;
292 }
293
294 return false;
295}
296
John Kesseniche01a9bc2016-03-12 20:11:22 -0700297// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600298// : sampler_declaration_dx9 post_decls SEMICOLON
John Kessenich13075c62017-04-11 09:51:32 -0600299// | fully_specified_type declarator_list SEMICOLON(optional for cbuffer/tbuffer)
John Kessenich630dd7d2016-06-12 23:52:12 -0600300// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600301// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600302// | typedef declaration
John Kessenich8f9fdc92017-03-30 16:22:26 -0600303// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
John Kessenich87142c72016-03-12 20:24:24 -0700304//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600305// declarator_list
306// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600307//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600308// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600309// : identifier array_specifier post_decls
310// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600311// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600312//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600313// Parsing has to go pretty far in to know whether it's a variable, prototype, or
314// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600315// as above. (The 'identifier' in the first item in init_declarator list is the
316// same as 'identifier' for function declarations.)
317//
John Kessenichca71d942017-03-07 20:44:09 -0700318// This can generate more than one subtree, one per initializer or a function body.
319// All initializer subtrees are put in their own aggregate node, making one top-level
320// node for all the initializers. Each function created is a top-level node to grow
321// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600322//
John Kessenichca71d942017-03-07 20:44:09 -0700323// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
324// each top-level node the declaration creates. Otherwise, if only one top-level
325// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700326//
John Kessenichca71d942017-03-07 20:44:09 -0700327bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700328{
John Kessenich8f9fdc92017-03-30 16:22:26 -0600329 // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
330 if (acceptTokenClass(EHTokNamespace)) {
331 HlslToken namespaceToken;
332 if (!acceptIdentifier(namespaceToken)) {
333 expected("namespace name");
334 return false;
335 }
336 parseContext.pushNamespace(*namespaceToken.string);
337 if (!acceptTokenClass(EHTokLeftBrace)) {
338 expected("{");
339 return false;
340 }
341 if (!acceptDeclarationList(nodeList)) {
342 expected("declaration list");
343 return false;
344 }
345 if (!acceptTokenClass(EHTokRightBrace)) {
346 expected("}");
347 return false;
348 }
349 parseContext.popNamespace();
350 return true;
351 }
352
John Kessenich54ee28f2017-03-11 14:13:00 -0700353 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600354
steve-lunarg1868b142016-10-20 13:07:10 -0600355 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700356 TFunctionDeclarator declarator;
357 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600358
John Kessenich5e69ec62016-07-05 00:02:40 -0600359 // typedef
360 bool typedefDecl = acceptTokenClass(EHTokTypedef);
361
John Kesseniche82061d2016-09-27 14:38:57 -0600362 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600363
364 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600365 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
366 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
367 // HLSL shaders, this will have to be a master level switch
368 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700369 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700370 // if (acceptSamplerDeclarationDX9(declaredType))
371 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600372
373 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700374 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700375 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600376
John Kessenich87142c72016-03-12 20:24:24 -0700377 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600378 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700379 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600380 while (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600381 const TString *fullName = idToken.string;
382 if (parseContext.symbolTable.atGlobalLevel())
383 parseContext.getFullNamespaceName(fullName);
John Kessenich78388722017-03-08 18:53:51 -0700384 if (peekTokenClass(EHTokLeftParen)) {
385 // looks like function parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600386
John Kessenich78388722017-03-08 18:53:51 -0700387 // Potentially rename shader entry point function. No-op most of the time.
John Kessenich8f9fdc92017-03-30 16:22:26 -0600388 parseContext.renameShaderFunction(fullName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600389
John Kessenich78388722017-03-08 18:53:51 -0700390 // function_parameters
John Kessenich8f9fdc92017-03-30 16:22:26 -0600391 declarator.function = new TFunction(fullName, declaredType);
John Kessenich088d52b2017-03-11 17:55:28 -0700392 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700393 expected("function parameter list");
394 return false;
395 }
396
John Kessenich630dd7d2016-06-12 23:52:12 -0600397 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700398 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600399
John Kessenichd5ed0b62016-07-04 17:32:45 -0600400 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700401 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600402 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700403 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600404 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600405 if (typedefDecl)
406 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700407 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600408 } else {
409 if (typedefDecl)
410 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700411 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600412 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600413 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600414 // A variable declaration. Fix the storage qualifier if it's a global.
415 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
416 declaredType.getQualifier().storage = EvqUniform;
417
John Kessenichecba76f2017-01-06 00:34:48 -0700418 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600419 // the number of types can expand when arrayness is different.
420 TType variableType;
421 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600422
John Kesseniche82061d2016-09-27 14:38:57 -0600423 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600424 TArraySizes* arraySizes = nullptr;
425 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600426
John Kesseniche82061d2016-09-27 14:38:57 -0600427 // Fix arrayness in the variableType
428 if (declaredType.isImplicitlySizedArray()) {
429 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
430 // of different sizes, for this case sharing the shallow copy of arrayness
431 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
432 variableType.newArraySizes(declaredType.getArraySizes());
433 }
434 if (arraySizes || variableType.isArray()) {
435 // In the most general case, arrayness is potentially coming both from the
436 // declared type and from the variable: "int[] a[];" or just one or the other.
437 // Merge it all to the variableType, so all arrayness is part of the variableType.
438 parseContext.arrayDimMerge(variableType, arraySizes);
439 }
440
LoopDawg4886f692016-06-29 10:58:58 -0600441 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600442 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600443 if (! acceptSamplerState())
444 return false;
445 }
446
John Kessenichd5ed0b62016-07-04 17:32:45 -0600447 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600448 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600449
450 // EQUAL assignment_expression
451 TIntermTyped* expressionNode = nullptr;
452 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600453 if (typedefDecl)
454 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600455 if (! acceptAssignmentExpression(expressionNode)) {
456 expected("initializer");
457 return false;
458 }
459 }
460
John Kessenich6dbc0a72016-09-27 19:13:05 -0600461 // TODO: things scoped within an annotation need their own name space;
462 // TODO: strings are not yet handled.
463 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
464 if (typedefDecl)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600465 parseContext.declareTypedef(idToken.loc, *fullName, variableType);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600466 else if (variableType.getBasicType() == EbtBlock) {
steve-lunarga766b832017-04-25 09:30:28 -0600467 parseContext.declareBlock(idToken.loc, variableType, fullName,
468 variableType.isArray() ? &variableType.getArraySizes() : nullptr);
steve-lunarg8e26feb2017-04-10 08:19:21 -0600469 parseContext.declareStructBufferCounter(idToken.loc, variableType, *fullName);
470 } else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700471 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600472 // this isn't really an individual variable, but a member of the $Global buffer
John Kessenich8f9fdc92017-03-30 16:22:26 -0600473 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600474 } else {
475 // Declare the variable and add any initializer code to the AST.
476 // The top-level node is always made into an aggregate, as that's
477 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700478 initializers = intermediate.growAggregate(initializers,
John Kessenich8f9fdc92017-03-30 16:22:26 -0600479 parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
John Kessenichca71d942017-03-07 20:44:09 -0700480 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600481 }
482 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600483 }
John Kessenich5f934b02016-03-13 17:58:25 -0600484 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600485
486 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700487 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600488 continue;
489 }
490 };
491
John Kessenichca71d942017-03-07 20:44:09 -0700492 // The top-level initializer node is a sequence.
493 if (initializers != nullptr)
494 initializers->setOperator(EOpSequence);
495
496 // Add the initializers' aggregate to the nodeList we were handed.
497 if (nodeList)
498 nodeList = intermediate.growAggregate(nodeList, initializers);
499 else
500 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700501
John Kessenich13075c62017-04-11 09:51:32 -0600502 // SEMICOLON(optional for cbuffer/tbuffer)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600503 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich13075c62017-04-11 09:51:32 -0600504 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma) {
505 // This may have been a false detection of what appeared to be a declaration, but
506 // was actually an assignment such as "float = 4", where "float" is an identifier.
507 // We put the token back to let further parsing happen for cases where that may
508 // happen. This errors on the side of caution, and mostly triggers the error.
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700509 recedeToken();
John Kessenich13075c62017-04-11 09:51:32 -0600510 return false;
511 } else if (declaredType.getBasicType() == EbtBlock) {
512 // cbuffer, et. al. (but not struct) don't have an ending semicolon
513 return true;
514 } else {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700515 expected(";");
John Kessenich13075c62017-04-11 09:51:32 -0600516 return false;
517 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600518 }
John Kessenichecba76f2017-01-06 00:34:48 -0700519
John Kesseniche01a9bc2016-03-12 20:11:22 -0700520 return true;
521}
522
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600523// control_declaration
524// : fully_specified_type identifier EQUAL expression
525//
526bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
527{
528 node = nullptr;
529
530 // fully_specified_type
531 TType type;
532 if (! acceptFullySpecifiedType(type))
533 return false;
534
John Kessenich057df292017-03-06 18:18:37 -0700535 // filter out type casts
536 if (peekTokenClass(EHTokLeftParen)) {
537 recedeToken();
538 return false;
539 }
540
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600541 // identifier
542 HlslToken idToken;
543 if (! acceptIdentifier(idToken)) {
544 expected("identifier");
545 return false;
546 }
547
548 // EQUAL
549 TIntermTyped* expressionNode = nullptr;
550 if (! acceptTokenClass(EHTokAssign)) {
551 expected("=");
552 return false;
553 }
554
555 // expression
556 if (! acceptExpression(expressionNode)) {
557 expected("initializer");
558 return false;
559 }
560
John Kesseniche82061d2016-09-27 14:38:57 -0600561 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600562
563 return true;
564}
565
John Kessenich87142c72016-03-12 20:24:24 -0700566// fully_specified_type
567// : type_specifier
568// | type_qualifier type_specifier
569//
570bool HlslGrammar::acceptFullySpecifiedType(TType& type)
571{
John Kessenich54ee28f2017-03-11 14:13:00 -0700572 TIntermNode* nodeList = nullptr;
573 return acceptFullySpecifiedType(type, nodeList);
574}
575bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
576{
John Kessenich87142c72016-03-12 20:24:24 -0700577 // type_qualifier
578 TQualifier qualifier;
579 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600580 if (! acceptQualifier(qualifier))
581 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600582 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700583
584 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700585 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700586 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700587 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700588 // qualifier. Back it out, if we did.
589 if (qualifier.sample)
590 recedeToken();
591
John Kessenich87142c72016-03-12 20:24:24 -0700592 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700593 }
John Kessenich3d157c52016-07-25 16:05:33 -0600594 if (type.getBasicType() == EbtBlock) {
595 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600596 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600597 // further, it can create an anonymous instance of the block
John Kessenich13075c62017-04-11 09:51:32 -0600598 if (peek() != EHTokIdentifier)
John Kessenich3d157c52016-07-25 16:05:33 -0600599 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600600 } else {
601 // Some qualifiers are set when parsing the type. Merge those with
602 // whatever comes from acceptQualifier.
603 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700604
steve-lunargbb0183f2016-10-04 16:58:14 -0600605 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600606 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700607
steve-lunarg08e0c082017-03-29 20:01:13 -0600608 if (type.getQualifier().storage == EvqOut ||
steve-lunarg5da1f032017-02-12 17:50:28 -0700609 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700610 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700611 qualifier.readonly = type.getQualifier().readonly;
612 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700613
steve-lunarg08e0c082017-03-29 20:01:13 -0600614 if (type.getQualifier().builtIn != EbvNone)
615 qualifier.builtIn = type.getQualifier().builtIn;
616
steve-lunargf49cdf42016-11-17 15:04:20 -0700617 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600618 }
John Kessenich87142c72016-03-12 20:24:24 -0700619
620 return true;
621}
622
John Kessenich630dd7d2016-06-12 23:52:12 -0600623// type_qualifier
624// : qualifier qualifier ...
625//
626// Zero or more of these, so this can't return false.
627//
John Kessenichb9e39122016-08-17 10:22:08 -0600628bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700629{
John Kessenich630dd7d2016-06-12 23:52:12 -0600630 do {
631 switch (peek()) {
632 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600633 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600634 break;
635 case EHTokExtern:
636 // TODO: no meaning in glslang?
637 break;
638 case EHTokShared:
639 // TODO: hint
640 break;
641 case EHTokGroupShared:
642 qualifier.storage = EvqShared;
643 break;
644 case EHTokUniform:
645 qualifier.storage = EvqUniform;
646 break;
647 case EHTokConst:
648 qualifier.storage = EvqConst;
649 break;
650 case EHTokVolatile:
651 qualifier.volatil = true;
652 break;
653 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600654 qualifier.smooth = true;
655 break;
656 case EHTokCentroid:
657 qualifier.centroid = true;
658 break;
659 case EHTokNointerpolation:
660 qualifier.flat = true;
661 break;
662 case EHTokNoperspective:
663 qualifier.nopersp = true;
664 break;
665 case EHTokSample:
666 qualifier.sample = true;
667 break;
668 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600669 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600670 break;
671 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600672 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600673 break;
674 case EHTokPrecise:
675 qualifier.noContraction = true;
676 break;
LoopDawg9249c702016-07-12 20:44:32 -0600677 case EHTokIn:
678 qualifier.storage = EvqIn;
679 break;
680 case EHTokOut:
681 qualifier.storage = EvqOut;
682 break;
683 case EHTokInOut:
684 qualifier.storage = EvqInOut;
685 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600686 case EHTokLayout:
687 if (! acceptLayoutQualifierList(qualifier))
688 return false;
689 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700690 case EHTokGloballyCoherent:
691 qualifier.coherent = true;
692 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600693 case EHTokInline:
694 // TODO: map this to SPIR-V function control
695 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700696
697 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
698 // for output variables.
699 case EHTokPoint:
700 qualifier.storage = EvqIn;
701 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
702 return false;
703 break;
704 case EHTokLine:
705 qualifier.storage = EvqIn;
706 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
707 return false;
708 break;
709 case EHTokTriangle:
710 qualifier.storage = EvqIn;
711 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
712 return false;
713 break;
714 case EHTokLineAdj:
715 qualifier.storage = EvqIn;
716 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
717 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700718 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700719 case EHTokTriangleAdj:
720 qualifier.storage = EvqIn;
721 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
722 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700723 break;
724
John Kessenich630dd7d2016-06-12 23:52:12 -0600725 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600726 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600727 }
728 advanceToken();
729 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700730}
731
John Kessenichb9e39122016-08-17 10:22:08 -0600732// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600733// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600734//
735// layout_qualifier
736// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600737// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600738//
739// Zero or more of these, so this can't return false.
740//
741bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
742{
743 if (! acceptTokenClass(EHTokLayout))
744 return false;
745
746 // LEFT_PAREN
747 if (! acceptTokenClass(EHTokLeftParen))
748 return false;
749
750 do {
751 // identifier
752 HlslToken idToken;
753 if (! acceptIdentifier(idToken))
754 break;
755
756 // EQUAL expression
757 if (acceptTokenClass(EHTokAssign)) {
758 TIntermTyped* expr;
759 if (! acceptConditionalExpression(expr)) {
760 expected("expression");
761 return false;
762 }
763 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
764 } else
765 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
766
767 // COMMA
768 if (! acceptTokenClass(EHTokComma))
769 break;
770 } while (true);
771
772 // RIGHT_PAREN
773 if (! acceptTokenClass(EHTokRightParen)) {
774 expected(")");
775 return false;
776 }
777
778 return true;
779}
780
LoopDawg6daaa4f2016-06-23 19:13:48 -0600781// template_type
782// : FLOAT
783// | DOUBLE
784// | INT
785// | DWORD
786// | UINT
787// | BOOL
788//
steve-lunargf49cdf42016-11-17 15:04:20 -0700789bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600790{
791 switch (peek()) {
792 case EHTokFloat:
793 basicType = EbtFloat;
794 break;
795 case EHTokDouble:
796 basicType = EbtDouble;
797 break;
798 case EHTokInt:
799 case EHTokDword:
800 basicType = EbtInt;
801 break;
802 case EHTokUint:
803 basicType = EbtUint;
804 break;
805 case EHTokBool:
806 basicType = EbtBool;
807 break;
808 default:
809 return false;
810 }
811
812 advanceToken();
813
814 return true;
815}
816
817// vector_template_type
818// : VECTOR
819// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
820//
821bool HlslGrammar::acceptVectorTemplateType(TType& type)
822{
823 if (! acceptTokenClass(EHTokVector))
824 return false;
825
826 if (! acceptTokenClass(EHTokLeftAngle)) {
827 // in HLSL, 'vector' alone means float4.
828 new(&type) TType(EbtFloat, EvqTemporary, 4);
829 return true;
830 }
831
832 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700833 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600834 expected("scalar type");
835 return false;
836 }
837
838 // COMMA
839 if (! acceptTokenClass(EHTokComma)) {
840 expected(",");
841 return false;
842 }
843
844 // integer
845 if (! peekTokenClass(EHTokIntConstant)) {
846 expected("literal integer");
847 return false;
848 }
849
850 TIntermTyped* vecSize;
851 if (! acceptLiteral(vecSize))
852 return false;
853
854 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
855
856 new(&type) TType(basicType, EvqTemporary, vecSizeI);
857
858 if (vecSizeI == 1)
859 type.makeVector();
860
861 if (!acceptTokenClass(EHTokRightAngle)) {
862 expected("right angle bracket");
863 return false;
864 }
865
866 return true;
867}
868
869// matrix_template_type
870// : MATRIX
871// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
872//
873bool HlslGrammar::acceptMatrixTemplateType(TType& type)
874{
875 if (! acceptTokenClass(EHTokMatrix))
876 return false;
877
878 if (! acceptTokenClass(EHTokLeftAngle)) {
879 // in HLSL, 'matrix' alone means float4x4.
880 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
881 return true;
882 }
883
884 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700885 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600886 expected("scalar type");
887 return false;
888 }
889
890 // COMMA
891 if (! acceptTokenClass(EHTokComma)) {
892 expected(",");
893 return false;
894 }
895
896 // integer rows
897 if (! peekTokenClass(EHTokIntConstant)) {
898 expected("literal integer");
899 return false;
900 }
901
902 TIntermTyped* rows;
903 if (! acceptLiteral(rows))
904 return false;
905
906 // COMMA
907 if (! acceptTokenClass(EHTokComma)) {
908 expected(",");
909 return false;
910 }
John Kessenichecba76f2017-01-06 00:34:48 -0700911
LoopDawg6daaa4f2016-06-23 19:13:48 -0600912 // integer cols
913 if (! peekTokenClass(EHTokIntConstant)) {
914 expected("literal integer");
915 return false;
916 }
917
918 TIntermTyped* cols;
919 if (! acceptLiteral(cols))
920 return false;
921
922 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600923 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
924 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600925
926 if (!acceptTokenClass(EHTokRightAngle)) {
927 expected("right angle bracket");
928 return false;
929 }
930
931 return true;
932}
933
steve-lunargf49cdf42016-11-17 15:04:20 -0700934// layout_geometry
935// : LINESTREAM
936// | POINTSTREAM
937// | TRIANGLESTREAM
938//
939bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
940{
941 // read geometry type
942 const EHlslTokenClass geometryType = peek();
943
944 switch (geometryType) {
945 case EHTokPointStream: geometry = ElgPoints; break;
946 case EHTokLineStream: geometry = ElgLineStrip; break;
947 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
948 default:
949 return false; // not a layout geometry
950 }
951
952 advanceToken(); // consume the layout keyword
953 return true;
954}
955
steve-lunarg858c9282017-01-07 08:54:10 -0700956// tessellation_decl_type
957// : INPUTPATCH
958// | OUTPUTPATCH
959//
steve-lunarg067eb9b2017-04-01 15:34:48 -0600960bool HlslGrammar::acceptTessellationDeclType(TBuiltInVariable& patchType)
steve-lunarg858c9282017-01-07 08:54:10 -0700961{
962 // read geometry type
963 const EHlslTokenClass tessType = peek();
964
965 switch (tessType) {
steve-lunarg067eb9b2017-04-01 15:34:48 -0600966 case EHTokInputPatch: patchType = EbvInputPatch; break;
967 case EHTokOutputPatch: patchType = EbvOutputPatch; break;
steve-lunarg858c9282017-01-07 08:54:10 -0700968 default:
969 return false; // not a tessellation decl
970 }
971
972 advanceToken(); // consume the keyword
973 return true;
974}
975
976// tessellation_patch_template_type
977// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
978//
979bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
980{
steve-lunarg067eb9b2017-04-01 15:34:48 -0600981 TBuiltInVariable patchType;
982
983 if (! acceptTessellationDeclType(patchType))
steve-lunarg858c9282017-01-07 08:54:10 -0700984 return false;
985
986 if (! acceptTokenClass(EHTokLeftAngle))
987 return false;
988
989 if (! acceptType(type)) {
990 expected("tessellation patch type");
991 return false;
992 }
993
994 if (! acceptTokenClass(EHTokComma))
995 return false;
996
997 // integer size
998 if (! peekTokenClass(EHTokIntConstant)) {
999 expected("literal integer");
1000 return false;
1001 }
1002
1003 TIntermTyped* size;
1004 if (! acceptLiteral(size))
1005 return false;
1006
1007 TArraySizes* arraySizes = new TArraySizes;
1008 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1009 type.newArraySizes(*arraySizes);
steve-lunarg067eb9b2017-04-01 15:34:48 -06001010 type.getQualifier().builtIn = patchType;
steve-lunarg858c9282017-01-07 08:54:10 -07001011
1012 if (! acceptTokenClass(EHTokRightAngle)) {
1013 expected("right angle bracket");
1014 return false;
1015 }
1016
1017 return true;
1018}
1019
steve-lunargf49cdf42016-11-17 15:04:20 -07001020// stream_out_template_type
1021// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1022//
1023bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1024{
1025 geometry = ElgNone;
1026
1027 if (! acceptOutputPrimitiveGeometry(geometry))
1028 return false;
1029
1030 if (! acceptTokenClass(EHTokLeftAngle))
1031 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001032
steve-lunargf49cdf42016-11-17 15:04:20 -07001033 if (! acceptType(type)) {
1034 expected("stream output type");
1035 return false;
1036 }
1037
steve-lunarg08e0c082017-03-29 20:01:13 -06001038 type.getQualifier().storage = EvqOut;
1039 type.getQualifier().builtIn = EbvGsOutputStream;
steve-lunargf49cdf42016-11-17 15:04:20 -07001040
1041 if (! acceptTokenClass(EHTokRightAngle)) {
1042 expected("right angle bracket");
1043 return false;
1044 }
1045
1046 return true;
1047}
John Kessenichecba76f2017-01-06 00:34:48 -07001048
John Kessenicha1e2d492016-09-20 13:22:58 -06001049// annotations
1050// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001051//
John Kessenicha1e2d492016-09-20 13:22:58 -06001052bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001053{
John Kessenicha1e2d492016-09-20 13:22:58 -06001054 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001055 return false;
1056
John Kessenicha1e2d492016-09-20 13:22:58 -06001057 // note that we are nesting a name space
1058 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001059
1060 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1061 do {
1062 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1063 while (acceptTokenClass(EHTokSemicolon))
1064 ;
1065
1066 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001067 break;
John Kessenich86f71382016-09-19 20:23:18 -06001068
1069 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001070 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001071 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001072 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001073 return false;
1074 }
1075 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001076
1077 parseContext.unnestAnnotations();
1078 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001079}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001080
LoopDawg4886f692016-06-29 10:58:58 -06001081// sampler_type
1082// : SAMPLER
1083// | SAMPLER1D
1084// | SAMPLER2D
1085// | SAMPLER3D
1086// | SAMPLERCUBE
1087// | SAMPLERSTATE
1088// | SAMPLERCOMPARISONSTATE
1089bool HlslGrammar::acceptSamplerType(TType& type)
1090{
1091 // read sampler type
1092 const EHlslTokenClass samplerType = peek();
1093
LoopDawga78b0292016-07-19 14:28:05 -06001094 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001095 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001096
LoopDawga78b0292016-07-19 14:28:05 -06001097 bool isShadow = false;
1098
LoopDawg4886f692016-06-29 10:58:58 -06001099 switch (samplerType) {
1100 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001101 case EHTokSampler1d: /*dim = Esd1D*/; break;
1102 case EHTokSampler2d: /*dim = Esd2D*/; break;
1103 case EHTokSampler3d: /*dim = Esd3D*/; break;
1104 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001105 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001106 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001107 default:
1108 return false; // not a sampler declaration
1109 }
1110
1111 advanceToken(); // consume the sampler type keyword
1112
1113 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001114
1115 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001116 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001117
1118 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1119
1120 return true;
1121}
1122
1123// texture_type
1124// | BUFFER
1125// | TEXTURE1D
1126// | TEXTURE1DARRAY
1127// | TEXTURE2D
1128// | TEXTURE2DARRAY
1129// | TEXTURE3D
1130// | TEXTURECUBE
1131// | TEXTURECUBEARRAY
1132// | TEXTURE2DMS
1133// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001134// | RWBUFFER
1135// | RWTEXTURE1D
1136// | RWTEXTURE1DARRAY
1137// | RWTEXTURE2D
1138// | RWTEXTURE2DARRAY
1139// | RWTEXTURE3D
1140
LoopDawg4886f692016-06-29 10:58:58 -06001141bool HlslGrammar::acceptTextureType(TType& type)
1142{
1143 const EHlslTokenClass textureType = peek();
1144
1145 TSamplerDim dim = EsdNone;
1146 bool array = false;
1147 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001148 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001149 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001150
1151 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001152 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001153 case EHTokTexture1d: dim = Esd1D; break;
1154 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1155 case EHTokTexture2d: dim = Esd2D; break;
1156 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1157 case EHTokTexture3d: dim = Esd3D; break;
1158 case EHTokTextureCube: dim = EsdCube; break;
1159 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1160 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1161 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1162 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1163 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1164 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1165 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1166 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1167 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001168 default:
1169 return false; // not a texture declaration
1170 }
1171
1172 advanceToken(); // consume the texture object keyword
1173
1174 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001175
LoopDawg4886f692016-06-29 10:58:58 -06001176 TIntermTyped* msCount = nullptr;
1177
steve-lunargbb0183f2016-10-04 16:58:14 -06001178 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001179 if (acceptTokenClass(EHTokLeftAngle)) {
1180 if (! acceptType(txType)) {
1181 expected("scalar or vector type");
1182 return false;
1183 }
1184
1185 const TBasicType basicRetType = txType.getBasicType() ;
1186
1187 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1188 unimplemented("basic type in texture");
1189 return false;
1190 }
1191
steve-lunargd53f7172016-07-27 15:46:48 -06001192 // Buffers can handle small mats if they fit in 4 components
1193 if (dim == EsdBuffer && txType.isMatrix()) {
1194 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1195 expected("components < 4 in matrix buffer type");
1196 return false;
1197 }
1198
1199 // TODO: except we don't handle it yet...
1200 unimplemented("matrix type in buffer");
1201 return false;
1202 }
1203
LoopDawg4886f692016-06-29 10:58:58 -06001204 if (!txType.isScalar() && !txType.isVector()) {
1205 expected("scalar or vector type");
1206 return false;
1207 }
1208
LoopDawg4886f692016-06-29 10:58:58 -06001209 if (ms && acceptTokenClass(EHTokComma)) {
1210 // read sample count for multisample types, if given
1211 if (! peekTokenClass(EHTokIntConstant)) {
1212 expected("multisample count");
1213 return false;
1214 }
1215
1216 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1217 return false;
1218 }
1219
1220 if (! acceptTokenClass(EHTokRightAngle)) {
1221 expected("right angle bracket");
1222 return false;
1223 }
1224 } else if (ms) {
1225 expected("texture type for multisample");
1226 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001227 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001228 expected("type for RWTexture/RWBuffer");
1229 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001230 }
1231
1232 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001233 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001234
1235 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001236 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001237
steve-lunarg4f2da272016-10-10 15:24:57 -06001238 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1239 if (image || dim == EsdBuffer)
1240 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001241
1242 // Non-image Buffers are combined
1243 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001244 sampler.set(txType.getBasicType(), dim, array);
1245 } else {
1246 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001247 if (image) {
1248 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1249 } else {
1250 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1251 }
steve-lunargd53f7172016-07-27 15:46:48 -06001252 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001253
1254 // Remember the declared vector size.
1255 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001256
steve-lunargbf1537f2017-03-31 17:40:09 -06001257 // Force uncombined, if necessary
1258 if (!combined)
1259 sampler.combined = false;
1260
LoopDawg4886f692016-06-29 10:58:58 -06001261 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001262 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001263
1264 return true;
1265}
1266
John Kessenich87142c72016-03-12 20:24:24 -07001267// If token is for a type, update 'type' with the type information,
1268// and return true and advance.
1269// Otherwise, return false, and don't advance
1270bool HlslGrammar::acceptType(TType& type)
1271{
John Kessenich54ee28f2017-03-11 14:13:00 -07001272 TIntermNode* nodeList = nullptr;
1273 return acceptType(type, nodeList);
1274}
1275bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1276{
steve-lunarg3226b082016-10-26 19:18:55 -06001277 // Basic types for min* types, broken out here in case of future
1278 // changes, e.g, to use native halfs.
1279 static const TBasicType min16float_bt = EbtFloat;
1280 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001281 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001282 static const TBasicType min16int_bt = EbtInt;
1283 static const TBasicType min12int_bt = EbtInt;
1284 static const TBasicType min16uint_bt = EbtUint;
1285
John Kessenich0320d092017-06-13 22:22:52 -06001286 // Some types might have turned into identifiers. Take the hit for checking
1287 // when this has happened.
1288 if (typeIdentifiers) {
1289 const char* identifierString = getTypeString(peek());
1290 if (identifierString != nullptr) {
1291 TString name = identifierString;
1292 // if it's an identifier, it's not a type
1293 if (parseContext.symbolTable.find(name) != nullptr)
1294 return false;
1295 }
1296 }
1297
John Kessenich9c86c6a2016-05-03 22:49:24 -06001298 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001299 case EHTokVector:
1300 return acceptVectorTemplateType(type);
1301 break;
1302
1303 case EHTokMatrix:
1304 return acceptMatrixTemplateType(type);
1305 break;
1306
steve-lunargf49cdf42016-11-17 15:04:20 -07001307 case EHTokPointStream: // fall through
1308 case EHTokLineStream: // ...
1309 case EHTokTriangleStream: // ...
1310 {
1311 TLayoutGeometry geometry;
1312 if (! acceptStreamOutTemplateType(type, geometry))
1313 return false;
1314
1315 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1316 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001317
steve-lunargf49cdf42016-11-17 15:04:20 -07001318 return true;
1319 }
1320
steve-lunarg858c9282017-01-07 08:54:10 -07001321 case EHTokInputPatch: // fall through
1322 case EHTokOutputPatch: // ...
1323 {
1324 if (! acceptTessellationPatchTemplateType(type))
1325 return false;
1326
1327 return true;
1328 }
1329
LoopDawg4886f692016-06-29 10:58:58 -06001330 case EHTokSampler: // fall through
1331 case EHTokSampler1d: // ...
1332 case EHTokSampler2d: // ...
1333 case EHTokSampler3d: // ...
1334 case EHTokSamplerCube: // ...
1335 case EHTokSamplerState: // ...
1336 case EHTokSamplerComparisonState: // ...
1337 return acceptSamplerType(type);
1338 break;
1339
1340 case EHTokBuffer: // fall through
1341 case EHTokTexture1d: // ...
1342 case EHTokTexture1darray: // ...
1343 case EHTokTexture2d: // ...
1344 case EHTokTexture2darray: // ...
1345 case EHTokTexture3d: // ...
1346 case EHTokTextureCube: // ...
1347 case EHTokTextureCubearray: // ...
1348 case EHTokTexture2DMS: // ...
1349 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001350 case EHTokRWTexture1d: // ...
1351 case EHTokRWTexture1darray: // ...
1352 case EHTokRWTexture2d: // ...
1353 case EHTokRWTexture2darray: // ...
1354 case EHTokRWTexture3d: // ...
1355 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001356 return acceptTextureType(type);
1357 break;
1358
steve-lunarg5da1f032017-02-12 17:50:28 -07001359 case EHTokAppendStructuredBuffer:
1360 case EHTokByteAddressBuffer:
1361 case EHTokConsumeStructuredBuffer:
1362 case EHTokRWByteAddressBuffer:
1363 case EHTokRWStructuredBuffer:
1364 case EHTokStructuredBuffer:
1365 return acceptStructBufferType(type);
1366 break;
1367
steve-lunarga766b832017-04-25 09:30:28 -06001368 case EHTokConstantBuffer:
1369 return acceptConstantBufferType(type);
1370
John Kessenich27ffb292017-03-03 17:01:01 -07001371 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001372 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001373 case EHTokCBuffer:
1374 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001375 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001376
1377 case EHTokIdentifier:
1378 // An identifier could be for a user-defined type.
1379 // Note we cache the symbol table lookup, to save for a later rule
1380 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001381 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001382 advanceToken();
1383 return true;
1384 } else
1385 return false;
1386
John Kessenich71351de2016-06-08 12:50:56 -06001387 case EHTokVoid:
1388 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001389 break;
John Kessenich71351de2016-06-08 12:50:56 -06001390
John Kessenicha1e2d492016-09-20 13:22:58 -06001391 case EHTokString:
1392 new(&type) TType(EbtString);
1393 break;
1394
John Kessenich87142c72016-03-12 20:24:24 -07001395 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001396 new(&type) TType(EbtFloat);
1397 break;
John Kessenich87142c72016-03-12 20:24:24 -07001398 case EHTokFloat1:
1399 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001400 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001401 break;
John Kessenich87142c72016-03-12 20:24:24 -07001402 case EHTokFloat2:
1403 new(&type) TType(EbtFloat, EvqTemporary, 2);
1404 break;
1405 case EHTokFloat3:
1406 new(&type) TType(EbtFloat, EvqTemporary, 3);
1407 break;
1408 case EHTokFloat4:
1409 new(&type) TType(EbtFloat, EvqTemporary, 4);
1410 break;
1411
John Kessenich71351de2016-06-08 12:50:56 -06001412 case EHTokDouble:
1413 new(&type) TType(EbtDouble);
1414 break;
1415 case EHTokDouble1:
1416 new(&type) TType(EbtDouble);
1417 type.makeVector();
1418 break;
1419 case EHTokDouble2:
1420 new(&type) TType(EbtDouble, EvqTemporary, 2);
1421 break;
1422 case EHTokDouble3:
1423 new(&type) TType(EbtDouble, EvqTemporary, 3);
1424 break;
1425 case EHTokDouble4:
1426 new(&type) TType(EbtDouble, EvqTemporary, 4);
1427 break;
1428
1429 case EHTokInt:
1430 case EHTokDword:
1431 new(&type) TType(EbtInt);
1432 break;
1433 case EHTokInt1:
1434 new(&type) TType(EbtInt);
1435 type.makeVector();
1436 break;
John Kessenich87142c72016-03-12 20:24:24 -07001437 case EHTokInt2:
1438 new(&type) TType(EbtInt, EvqTemporary, 2);
1439 break;
1440 case EHTokInt3:
1441 new(&type) TType(EbtInt, EvqTemporary, 3);
1442 break;
1443 case EHTokInt4:
1444 new(&type) TType(EbtInt, EvqTemporary, 4);
1445 break;
1446
John Kessenich71351de2016-06-08 12:50:56 -06001447 case EHTokUint:
1448 new(&type) TType(EbtUint);
1449 break;
1450 case EHTokUint1:
1451 new(&type) TType(EbtUint);
1452 type.makeVector();
1453 break;
1454 case EHTokUint2:
1455 new(&type) TType(EbtUint, EvqTemporary, 2);
1456 break;
1457 case EHTokUint3:
1458 new(&type) TType(EbtUint, EvqTemporary, 3);
1459 break;
1460 case EHTokUint4:
1461 new(&type) TType(EbtUint, EvqTemporary, 4);
1462 break;
1463
1464 case EHTokBool:
1465 new(&type) TType(EbtBool);
1466 break;
1467 case EHTokBool1:
1468 new(&type) TType(EbtBool);
1469 type.makeVector();
1470 break;
John Kessenich87142c72016-03-12 20:24:24 -07001471 case EHTokBool2:
1472 new(&type) TType(EbtBool, EvqTemporary, 2);
1473 break;
1474 case EHTokBool3:
1475 new(&type) TType(EbtBool, EvqTemporary, 3);
1476 break;
1477 case EHTokBool4:
1478 new(&type) TType(EbtBool, EvqTemporary, 4);
1479 break;
1480
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001481 case EHTokHalf:
John Kessenich96f65522017-06-06 23:35:25 -06001482 new(&type) TType(half_bt, EvqTemporary);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001483 break;
1484 case EHTokHalf1:
John Kessenich96f65522017-06-06 23:35:25 -06001485 new(&type) TType(half_bt, EvqTemporary);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001486 type.makeVector();
1487 break;
1488 case EHTokHalf2:
John Kessenich96f65522017-06-06 23:35:25 -06001489 new(&type) TType(half_bt, EvqTemporary, 2);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001490 break;
1491 case EHTokHalf3:
John Kessenich96f65522017-06-06 23:35:25 -06001492 new(&type) TType(half_bt, EvqTemporary, 3);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001493 break;
1494 case EHTokHalf4:
John Kessenich96f65522017-06-06 23:35:25 -06001495 new(&type) TType(half_bt, EvqTemporary, 4);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001496 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001497
steve-lunarg3226b082016-10-26 19:18:55 -06001498 case EHTokMin16float:
1499 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1500 break;
1501 case EHTokMin16float1:
1502 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1503 type.makeVector();
1504 break;
1505 case EHTokMin16float2:
1506 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1507 break;
1508 case EHTokMin16float3:
1509 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1510 break;
1511 case EHTokMin16float4:
1512 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1513 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001514
steve-lunarg3226b082016-10-26 19:18:55 -06001515 case EHTokMin10float:
1516 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1517 break;
1518 case EHTokMin10float1:
1519 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1520 type.makeVector();
1521 break;
1522 case EHTokMin10float2:
1523 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1524 break;
1525 case EHTokMin10float3:
1526 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1527 break;
1528 case EHTokMin10float4:
1529 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1530 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001531
steve-lunarg3226b082016-10-26 19:18:55 -06001532 case EHTokMin16int:
1533 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1534 break;
1535 case EHTokMin16int1:
1536 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1537 type.makeVector();
1538 break;
1539 case EHTokMin16int2:
1540 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1541 break;
1542 case EHTokMin16int3:
1543 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1544 break;
1545 case EHTokMin16int4:
1546 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1547 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001548
steve-lunarg3226b082016-10-26 19:18:55 -06001549 case EHTokMin12int:
1550 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1551 break;
1552 case EHTokMin12int1:
1553 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1554 type.makeVector();
1555 break;
1556 case EHTokMin12int2:
1557 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1558 break;
1559 case EHTokMin12int3:
1560 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1561 break;
1562 case EHTokMin12int4:
1563 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1564 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001565
steve-lunarg3226b082016-10-26 19:18:55 -06001566 case EHTokMin16uint:
1567 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1568 break;
1569 case EHTokMin16uint1:
1570 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1571 type.makeVector();
1572 break;
1573 case EHTokMin16uint2:
1574 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1575 break;
1576 case EHTokMin16uint3:
1577 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1578 break;
1579 case EHTokMin16uint4:
1580 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1581 break;
1582
John Kessenich0133c122016-05-20 12:17:26 -06001583 case EHTokInt1x1:
1584 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1585 break;
1586 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001587 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001588 break;
1589 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001590 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001591 break;
1592 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001593 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001594 break;
1595 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001596 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001597 break;
1598 case EHTokInt2x2:
1599 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1600 break;
1601 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001603 break;
1604 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001605 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001606 break;
1607 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001608 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001609 break;
1610 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001611 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001612 break;
1613 case EHTokInt3x3:
1614 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1615 break;
1616 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001618 break;
1619 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001621 break;
1622 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001623 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001624 break;
1625 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001626 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001627 break;
1628 case EHTokInt4x4:
1629 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1630 break;
1631
John Kessenich71351de2016-06-08 12:50:56 -06001632 case EHTokUint1x1:
1633 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1634 break;
1635 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001636 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001637 break;
1638 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001639 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001640 break;
1641 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001642 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001643 break;
1644 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001645 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001646 break;
1647 case EHTokUint2x2:
1648 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1649 break;
1650 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001651 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001652 break;
1653 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001654 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001655 break;
1656 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001657 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001658 break;
1659 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001660 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001661 break;
1662 case EHTokUint3x3:
1663 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1664 break;
1665 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001666 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001667 break;
1668 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001669 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001670 break;
1671 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001672 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001673 break;
1674 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001675 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001676 break;
1677 case EHTokUint4x4:
1678 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1679 break;
1680
1681 case EHTokBool1x1:
1682 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1683 break;
1684 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001685 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001686 break;
1687 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001688 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001689 break;
1690 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001691 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001692 break;
1693 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001694 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001695 break;
1696 case EHTokBool2x2:
1697 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1698 break;
1699 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001700 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001701 break;
1702 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001703 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001704 break;
1705 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001706 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001707 break;
1708 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001709 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001710 break;
1711 case EHTokBool3x3:
1712 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1713 break;
1714 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001715 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001716 break;
1717 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001718 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001719 break;
1720 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001721 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001722 break;
1723 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001724 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001725 break;
1726 case EHTokBool4x4:
1727 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1728 break;
1729
John Kessenich0133c122016-05-20 12:17:26 -06001730 case EHTokFloat1x1:
1731 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1732 break;
1733 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001734 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001735 break;
1736 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001737 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001738 break;
1739 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001740 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001741 break;
1742 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001743 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001744 break;
John Kessenich87142c72016-03-12 20:24:24 -07001745 case EHTokFloat2x2:
1746 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1747 break;
1748 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001749 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001750 break;
1751 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001752 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001753 break;
John Kessenich0133c122016-05-20 12:17:26 -06001754 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001755 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001756 break;
John Kessenich87142c72016-03-12 20:24:24 -07001757 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001758 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001759 break;
1760 case EHTokFloat3x3:
1761 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1762 break;
1763 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001764 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001765 break;
John Kessenich0133c122016-05-20 12:17:26 -06001766 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001767 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001768 break;
John Kessenich87142c72016-03-12 20:24:24 -07001769 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001770 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001771 break;
1772 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001773 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001774 break;
1775 case EHTokFloat4x4:
1776 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1777 break;
1778
John Kessenich96f65522017-06-06 23:35:25 -06001779 case EHTokHalf1x1:
1780 new(&type) TType(half_bt, EvqTemporary, 0, 1, 1);
1781 break;
1782 case EHTokHalf1x2:
1783 new(&type) TType(half_bt, EvqTemporary, 0, 1, 2);
1784 break;
1785 case EHTokHalf1x3:
1786 new(&type) TType(half_bt, EvqTemporary, 0, 1, 3);
1787 break;
1788 case EHTokHalf1x4:
1789 new(&type) TType(half_bt, EvqTemporary, 0, 1, 4);
1790 break;
1791 case EHTokHalf2x1:
1792 new(&type) TType(half_bt, EvqTemporary, 0, 2, 1);
1793 break;
1794 case EHTokHalf2x2:
1795 new(&type) TType(half_bt, EvqTemporary, 0, 2, 2);
1796 break;
1797 case EHTokHalf2x3:
1798 new(&type) TType(half_bt, EvqTemporary, 0, 2, 3);
1799 break;
1800 case EHTokHalf2x4:
1801 new(&type) TType(half_bt, EvqTemporary, 0, 2, 4);
1802 break;
1803 case EHTokHalf3x1:
1804 new(&type) TType(half_bt, EvqTemporary, 0, 3, 1);
1805 break;
1806 case EHTokHalf3x2:
1807 new(&type) TType(half_bt, EvqTemporary, 0, 3, 2);
1808 break;
1809 case EHTokHalf3x3:
1810 new(&type) TType(half_bt, EvqTemporary, 0, 3, 3);
1811 break;
1812 case EHTokHalf3x4:
1813 new(&type) TType(half_bt, EvqTemporary, 0, 3, 4);
1814 break;
1815 case EHTokHalf4x1:
1816 new(&type) TType(half_bt, EvqTemporary, 0, 4, 1);
1817 break;
1818 case EHTokHalf4x2:
1819 new(&type) TType(half_bt, EvqTemporary, 0, 4, 2);
1820 break;
1821 case EHTokHalf4x3:
1822 new(&type) TType(half_bt, EvqTemporary, 0, 4, 3);
1823 break;
1824 case EHTokHalf4x4:
1825 new(&type) TType(half_bt, EvqTemporary, 0, 4, 4);
1826 break;
1827
John Kessenich0133c122016-05-20 12:17:26 -06001828 case EHTokDouble1x1:
1829 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1830 break;
1831 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001832 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001833 break;
1834 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001835 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001836 break;
1837 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001838 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001839 break;
1840 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001841 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001842 break;
1843 case EHTokDouble2x2:
1844 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1845 break;
1846 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001847 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001848 break;
1849 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001850 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001851 break;
1852 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001853 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001854 break;
1855 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001856 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001857 break;
1858 case EHTokDouble3x3:
1859 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1860 break;
1861 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001862 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001863 break;
1864 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001865 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001866 break;
1867 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001868 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001869 break;
1870 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001871 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001872 break;
1873 case EHTokDouble4x4:
1874 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1875 break;
1876
John Kessenich87142c72016-03-12 20:24:24 -07001877 default:
1878 return false;
1879 }
1880
1881 advanceToken();
1882
1883 return true;
1884}
1885
John Kesseniche6e74942016-06-11 16:43:14 -06001886// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001887// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1888// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001889// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001890//
1891// struct_type
1892// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001893// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001894// | CBUFFER
1895// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001896//
John Kessenich54ee28f2017-03-11 14:13:00 -07001897bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001898{
John Kessenichb804de62016-09-05 12:19:18 -06001899 // This storage qualifier will tell us whether it's an AST
1900 // block type or just a generic structure type.
1901 TStorageQualifier storageQualifier = EvqTemporary;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001902 bool readonly = false;
John Kessenich3d157c52016-07-25 16:05:33 -06001903
1904 // CBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001905 if (acceptTokenClass(EHTokCBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001906 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001907 // TBUFFER
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001908 } else if (acceptTokenClass(EHTokTBuffer)) {
John Kessenichb804de62016-09-05 12:19:18 -06001909 storageQualifier = EvqBuffer;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001910 readonly = true;
1911 }
John Kessenich27ffb292017-03-03 17:01:01 -07001912 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001913 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001914 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001915 return false;
1916
1917 // IDENTIFIER
1918 TString structName = "";
1919 if (peekTokenClass(EHTokIdentifier)) {
1920 structName = *token.string;
1921 advanceToken();
1922 }
1923
John Kessenich3d157c52016-07-25 16:05:33 -06001924 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001925 TQualifier postDeclQualifier;
1926 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001927 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001928
John Kessenichf3d88bd2017-03-19 12:24:29 -06001929 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001930 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001931 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001932 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1933 // struct_type IDENTIFIER
1934 return true;
1935 } else {
1936 expected("{");
1937 return false;
1938 }
John Kesseniche6e74942016-06-11 16:43:14 -06001939 }
1940
John Kessenichf3d88bd2017-03-19 12:24:29 -06001941
John Kesseniche6e74942016-06-11 16:43:14 -06001942 // struct_declaration_list
1943 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001944 // Save each member function so they can be processed after we have a fully formed 'this'.
1945 TVector<TFunctionDeclarator> functionDeclarators;
1946
1947 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001948 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001949 parseContext.popNamespace();
1950
1951 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001952 expected("struct member declarations");
1953 return false;
1954 }
1955
1956 // RIGHT_BRACE
1957 if (! acceptTokenClass(EHTokRightBrace)) {
1958 expected("}");
1959 return false;
1960 }
1961
1962 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001963 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001964 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001965 else {
John Kessenich7735b942016-09-05 12:40:06 -06001966 postDeclQualifier.storage = storageQualifier;
steve-lunarg7b1dcd62017-04-20 13:16:23 -06001967 postDeclQualifier.readonly = readonly;
John Kessenich7735b942016-09-05 12:40:06 -06001968 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001969 }
John Kesseniche6e74942016-06-11 16:43:14 -06001970
John Kessenich727b3742017-02-03 17:57:55 -07001971 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001972
John Kessenich4960baa2017-03-19 18:09:59 -06001973 // For member functions: now that we know the type of 'this', go back and
1974 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1975 // - parse the functions, their tokens were saved for deferred parsing (now)
1976 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1977 // update signature
1978 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001979 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001980 }
1981
John Kessenichf3d88bd2017-03-19 12:24:29 -06001982 // All member functions get parsed inside the class/struct namespace and with the
1983 // class/struct members in a symbol-table level.
1984 parseContext.pushNamespace(structName);
John Kessenich0a2a0cd2017-05-16 23:16:26 -06001985 parseContext.pushThisScope(type, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001986 bool deferredSuccess = true;
1987 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1988 // parse body
1989 pushTokenStream(functionDeclarators[b].body);
1990 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1991 deferredSuccess = false;
1992 popTokenStream();
1993 }
John Kessenich37789792017-03-21 23:56:40 -06001994 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001995 parseContext.popNamespace();
1996
1997 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001998}
1999
steve-lunarga766b832017-04-25 09:30:28 -06002000// constantbuffer
2001// : CONSTANTBUFFER LEFT_ANGLE type RIGHT_ANGLE
2002bool HlslGrammar::acceptConstantBufferType(TType& type)
2003{
2004 if (! acceptTokenClass(EHTokConstantBuffer))
2005 return false;
2006
2007 if (! acceptTokenClass(EHTokLeftAngle)) {
2008 expected("left angle bracket");
2009 return false;
2010 }
2011
2012 TType templateType;
2013 if (! acceptType(templateType)) {
2014 expected("type");
2015 return false;
2016 }
2017
2018 if (! acceptTokenClass(EHTokRightAngle)) {
2019 expected("right angle bracket");
2020 return false;
2021 }
2022
2023 TQualifier postDeclQualifier;
2024 postDeclQualifier.clear();
2025 postDeclQualifier.storage = EvqUniform;
2026
2027 if (templateType.isStruct()) {
2028 // Make a block from the type parsed as the template argument
2029 TTypeList* typeList = templateType.getWritableStruct();
2030 new(&type) TType(typeList, "", postDeclQualifier); // sets EbtBlock
2031
2032 type.getQualifier().storage = EvqUniform;
2033
2034 return true;
2035 } else {
2036 parseContext.error(token.loc, "non-structure type in ConstantBuffer", "", "");
2037 return false;
2038 }
2039}
2040
steve-lunarg5da1f032017-02-12 17:50:28 -07002041// struct_buffer
2042// : APPENDSTRUCTUREDBUFFER
2043// | BYTEADDRESSBUFFER
2044// | CONSUMESTRUCTUREDBUFFER
2045// | RWBYTEADDRESSBUFFER
2046// | RWSTRUCTUREDBUFFER
2047// | STRUCTUREDBUFFER
2048bool HlslGrammar::acceptStructBufferType(TType& type)
2049{
2050 const EHlslTokenClass structBuffType = peek();
2051
2052 // TODO: globallycoherent
2053 bool hasTemplateType = true;
2054 bool readonly = false;
2055
2056 TStorageQualifier storage = EvqBuffer;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002057 TBuiltInVariable builtinType = EbvNone;
steve-lunarg5da1f032017-02-12 17:50:28 -07002058
2059 switch (structBuffType) {
2060 case EHTokAppendStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002061 builtinType = EbvAppendConsume;
2062 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07002063 case EHTokByteAddressBuffer:
2064 hasTemplateType = false;
2065 readonly = true;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002066 builtinType = EbvByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002067 break;
2068 case EHTokConsumeStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002069 builtinType = EbvAppendConsume;
2070 break;
steve-lunarg5da1f032017-02-12 17:50:28 -07002071 case EHTokRWByteAddressBuffer:
2072 hasTemplateType = false;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002073 builtinType = EbvRWByteAddressBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002074 break;
2075 case EHTokRWStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002076 builtinType = EbvRWStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002077 break;
2078 case EHTokStructuredBuffer:
steve-lunarg8e26feb2017-04-10 08:19:21 -06002079 builtinType = EbvStructuredBuffer;
steve-lunarg5da1f032017-02-12 17:50:28 -07002080 readonly = true;
2081 break;
2082 default:
2083 return false; // not a structure buffer type
2084 }
2085
2086 advanceToken(); // consume the structure keyword
2087
2088 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
2089 TType* templateType = new TType;
2090
2091 if (hasTemplateType) {
2092 if (! acceptTokenClass(EHTokLeftAngle)) {
2093 expected("left angle bracket");
2094 return false;
2095 }
2096
2097 if (! acceptType(*templateType)) {
2098 expected("type");
2099 return false;
2100 }
2101 if (! acceptTokenClass(EHTokRightAngle)) {
2102 expected("right angle bracket");
2103 return false;
2104 }
2105 } else {
2106 // byte address buffers have no explicit type.
2107 TType uintType(EbtUint, storage);
2108 templateType->shallowCopy(uintType);
2109 }
2110
2111 // Create an unsized array out of that type.
2112 // TODO: does this work if it's already an array type?
2113 TArraySizes unsizedArray;
2114 unsizedArray.addInnerSize(UnsizedArraySize);
2115 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002116 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002117
2118 // field name is canonical for all structbuffers
2119 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002120
steve-lunarg5da1f032017-02-12 17:50:28 -07002121 TTypeList* blockStruct = new TTypeList;
2122 TTypeLoc member = { templateType, token.loc };
2123 blockStruct->push_back(member);
2124
steve-lunargdd8287a2017-02-23 18:04:12 -07002125 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002126 TType blockType(blockStruct, "", templateType->getQualifier());
2127
steve-lunargdd8287a2017-02-23 18:04:12 -07002128 blockType.getQualifier().storage = storage;
2129 blockType.getQualifier().readonly = readonly;
steve-lunarg8e26feb2017-04-10 08:19:21 -06002130 blockType.getQualifier().builtIn = builtinType;
steve-lunargdd8287a2017-02-23 18:04:12 -07002131
2132 // We may have created an equivalent type before, in which case we should use its
2133 // deep structure.
2134 parseContext.shareStructBufferType(blockType);
2135
steve-lunarg5da1f032017-02-12 17:50:28 -07002136 type.shallowCopy(blockType);
2137
2138 return true;
2139}
2140
John Kesseniche6e74942016-06-11 16:43:14 -06002141// struct_declaration_list
2142// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2143//
2144// struct_declaration
2145// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002146// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002147//
2148// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002149// : IDENTIFIER post_decls
2150// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002151// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002152//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002153bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002154 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002155{
2156 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002157 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002158
2159 do {
2160 // success on seeing the RIGHT_BRACE coming up
2161 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002162 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002163
2164 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002165
2166 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002167
2168 // fully_specified_type
2169 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002170 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002171 expected("member type");
2172 return false;
2173 }
2174
2175 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002176 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002177 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002178 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002179 expected("member name");
2180 return false;
2181 }
2182
John Kessenich54ee28f2017-03-11 14:13:00 -07002183 if (peekTokenClass(EHTokLeftParen)) {
2184 // function_parameters
2185 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002186 declarators.resize(declarators.size() + 1);
2187 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002188 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2189 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002190 if (functionDefinitionAccepted)
2191 break;
2192 }
2193 expected("member-function definition");
2194 return false;
2195 } else {
2196 // add it to the list of members
2197 TTypeLoc member = { new TType(EbtVoid), token.loc };
2198 member.type->shallowCopy(memberType);
2199 member.type->setFieldName(*idToken.string);
2200 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002201
John Kessenich54ee28f2017-03-11 14:13:00 -07002202 // array_specifier
2203 TArraySizes* arraySizes = nullptr;
2204 acceptArraySpecifier(arraySizes);
2205 if (arraySizes)
2206 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002207
John Kessenich54ee28f2017-03-11 14:13:00 -07002208 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002209
John Kessenich54ee28f2017-03-11 14:13:00 -07002210 // EQUAL assignment_expression
2211 if (acceptTokenClass(EHTokAssign)) {
2212 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2213 TIntermTyped* expressionNode = nullptr;
2214 if (! acceptAssignmentExpression(expressionNode)) {
2215 expected("initializer");
2216 return false;
2217 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002218 }
2219 }
John Kesseniche6e74942016-06-11 16:43:14 -06002220 // success on seeing the SEMICOLON coming up
2221 if (peekTokenClass(EHTokSemicolon))
2222 break;
2223
2224 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002225 if (acceptTokenClass(EHTokComma))
2226 declarator_list = true;
2227 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002228 expected(",");
2229 return false;
2230 }
2231
2232 } while (true);
2233
2234 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002235 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002236 expected(";");
2237 return false;
2238 }
2239
2240 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002241
John Kessenichb16f7e62017-03-11 19:32:47 -07002242 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002243}
2244
John Kessenich54ee28f2017-03-11 14:13:00 -07002245// member_function_definition
2246// | function_parameters post_decls compound_statement
2247//
2248// Expects type to have EvqGlobal for a static member and
2249// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002250bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2251 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002252{
John Kessenich54ee28f2017-03-11 14:13:00 -07002253 bool accepted = false;
2254
John Kessenich4dc835c2017-03-28 23:43:10 -06002255 const TString* functionName = &memberName;
2256 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002257 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002258 if (type.getQualifier().storage == EvqTemporary)
2259 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002260 else
2261 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002262
2263 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002264 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002265 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002266 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002267
2268 // compound_statement (function body definition)
2269 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002270 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002271 declarator.body = new TVector<HlslToken>;
2272 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002273 }
2274 } else
2275 expected("function parameter list");
2276
John Kessenich54ee28f2017-03-11 14:13:00 -07002277 return accepted;
2278}
2279
John Kessenich5f934b02016-03-13 17:58:25 -06002280// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002281// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002282// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002283//
2284bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2285{
John Kessenich078d7f22016-03-14 10:02:11 -06002286 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002287 if (! acceptTokenClass(EHTokLeftParen))
2288 return false;
2289
John Kessenich71351de2016-06-08 12:50:56 -06002290 // VOID RIGHT_PAREN
2291 if (! acceptTokenClass(EHTokVoid)) {
2292 do {
2293 // parameter_declaration
2294 if (! acceptParameterDeclaration(function))
2295 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002296
John Kessenich71351de2016-06-08 12:50:56 -06002297 // COMMA
2298 if (! acceptTokenClass(EHTokComma))
2299 break;
2300 } while (true);
2301 }
John Kessenich5f934b02016-03-13 17:58:25 -06002302
John Kessenich078d7f22016-03-14 10:02:11 -06002303 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002304 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002305 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002306 return false;
2307 }
2308
2309 return true;
2310}
2311
steve-lunarg26d31452016-12-23 18:56:57 -07002312// default_parameter_declaration
2313// : EQUAL conditional_expression
2314// : EQUAL initializer
2315bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2316{
2317 node = nullptr;
2318
2319 // Valid not to have a default_parameter_declaration
2320 if (!acceptTokenClass(EHTokAssign))
2321 return true;
2322
2323 if (!acceptConditionalExpression(node)) {
2324 if (!acceptInitializer(node))
2325 return false;
2326
2327 // For initializer lists, we have to const-fold into a constructor for the type, so build
2328 // that.
John Kessenichc633f642017-04-03 21:48:37 -06002329 TFunction* constructor = parseContext.makeConstructorCall(token.loc, type);
steve-lunarg26d31452016-12-23 18:56:57 -07002330 if (constructor == nullptr) // cannot construct
2331 return false;
2332
2333 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002334 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002335 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002336
steve-lunarg26d31452016-12-23 18:56:57 -07002337 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2338 }
2339
2340 // If this is simply a constant, we can use it directly.
2341 if (node->getAsConstantUnion())
2342 return true;
2343
2344 // Otherwise, it has to be const-foldable.
2345 TIntermTyped* origNode = node;
2346
2347 node = intermediate.fold(node->getAsAggregate());
2348
2349 if (node != nullptr && origNode != node)
2350 return true;
2351
2352 parseContext.error(token.loc, "invalid default parameter value", "", "");
2353
2354 return false;
2355}
2356
John Kessenich5f934b02016-03-13 17:58:25 -06002357// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002358// : fully_specified_type post_decls [ = default_parameter_declaration ]
2359// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002360//
2361bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2362{
2363 // fully_specified_type
2364 TType* type = new TType;
2365 if (! acceptFullySpecifiedType(*type))
2366 return false;
2367
2368 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002369 HlslToken idToken;
2370 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002371
John Kessenich19b92ff2016-06-19 11:50:34 -06002372 // array_specifier
2373 TArraySizes* arraySizes = nullptr;
2374 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002375 if (arraySizes) {
2376 if (arraySizes->isImplicit()) {
2377 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2378 return false;
2379 }
2380
John Kessenich19b92ff2016-06-19 11:50:34 -06002381 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002382 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002383
2384 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002385 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002386
steve-lunarg26d31452016-12-23 18:56:57 -07002387 TIntermTyped* defaultValue;
2388 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2389 return false;
2390
John Kessenich5aa59e22016-06-17 15:50:47 -06002391 parseContext.paramFix(*type);
2392
steve-lunarg26d31452016-12-23 18:56:57 -07002393 // If any prior parameters have default values, all the parameters after that must as well.
2394 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2395 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2396 return false;
2397 }
2398
2399 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002400 function.addParameter(param);
2401
2402 return true;
2403}
2404
2405// Do the work to create the function definition in addition to
2406// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002407//
2408// If 'deferredTokens' are passed in, just get the token stream,
2409// don't process.
2410//
2411bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2412 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002413{
John Kessenich088d52b2017-03-11 17:55:28 -07002414 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002415
John Kessenichb16f7e62017-03-11 19:32:47 -07002416 if (deferredTokens)
2417 return captureBlockTokens(*deferredTokens);
2418 else
John Kessenich4960baa2017-03-19 18:09:59 -06002419 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002420}
2421
2422bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2423{
2424 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002425 TIntermNode* entryPointNode = nullptr;
2426
John Kessenich077e0522016-06-09 02:02:17 -06002427 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002428 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2429 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002430
2431 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002432 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002433 if (! acceptCompoundStatement(functionBody))
2434 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002435
John Kessenich54ee28f2017-03-11 14:13:00 -07002436 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002437 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002438
2439 // Hook up the 1 or 2 function definitions.
2440 nodeList = intermediate.growAggregate(nodeList, functionNode);
2441 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002442
2443 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002444}
2445
John Kessenich0d2b6de2016-06-05 11:23:11 -06002446// Accept an expression with parenthesis around it, where
2447// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002448// syntactically required ones like in "if ( expression )".
2449//
2450// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002451//
2452// Note this one is not set up to be speculative; as it gives
2453// errors if not found.
2454//
2455bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2456{
2457 // LEFT_PAREN
2458 if (! acceptTokenClass(EHTokLeftParen))
2459 expected("(");
2460
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002461 bool decl = false;
2462 TIntermNode* declNode = nullptr;
2463 decl = acceptControlDeclaration(declNode);
2464 if (decl) {
2465 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2466 expected("initialized declaration");
2467 return false;
2468 } else
2469 expression = declNode->getAsTyped();
2470 } else {
2471 // no declaration
2472 if (! acceptExpression(expression)) {
2473 expected("expression");
2474 return false;
2475 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002476 }
2477
2478 // RIGHT_PAREN
2479 if (! acceptTokenClass(EHTokRightParen))
2480 expected(")");
2481
2482 return true;
2483}
2484
John Kessenich34fb0362016-05-03 23:17:20 -06002485// The top-level full expression recognizer.
2486//
John Kessenich87142c72016-03-12 20:24:24 -07002487// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002488// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002489//
2490bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2491{
LoopDawgef764a22016-06-03 09:17:51 -06002492 node = nullptr;
2493
John Kessenich34fb0362016-05-03 23:17:20 -06002494 // assignment_expression
2495 if (! acceptAssignmentExpression(node))
2496 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002497
John Kessenich34fb0362016-05-03 23:17:20 -06002498 if (! peekTokenClass(EHTokComma))
2499 return true;
2500
2501 do {
2502 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002503 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002504 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002505
John Kessenich34fb0362016-05-03 23:17:20 -06002506 // ... assignment_expression
2507 TIntermTyped* rightNode = nullptr;
2508 if (! acceptAssignmentExpression(rightNode)) {
2509 expected("assignment expression");
2510 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002511 }
2512
John Kessenich34fb0362016-05-03 23:17:20 -06002513 node = intermediate.addComma(node, rightNode, loc);
2514
2515 if (! peekTokenClass(EHTokComma))
2516 return true;
2517 } while (true);
2518}
2519
John Kessenich07354242016-07-01 19:58:06 -06002520// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002521// : LEFT_BRACE RIGHT_BRACE
2522// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002523//
2524// initializer_list
2525// : assignment_expression COMMA assignment_expression COMMA ...
2526//
2527bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2528{
2529 // LEFT_BRACE
2530 if (! acceptTokenClass(EHTokLeftBrace))
2531 return false;
2532
John Kessenich98ad4852016-11-27 17:39:07 -07002533 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002534 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002535 if (acceptTokenClass(EHTokRightBrace)) {
2536 // a zero-length initializer list
2537 node = intermediate.makeAggregate(loc);
2538 return true;
2539 }
2540
2541 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002542 node = nullptr;
2543 do {
2544 // assignment_expression
2545 TIntermTyped* expr;
2546 if (! acceptAssignmentExpression(expr)) {
2547 expected("assignment expression in initializer list");
2548 return false;
2549 }
2550 node = intermediate.growAggregate(node, expr, loc);
2551
2552 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002553 if (acceptTokenClass(EHTokComma)) {
2554 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2555 return true;
John Kessenich07354242016-07-01 19:58:06 -06002556 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002557 }
John Kessenich07354242016-07-01 19:58:06 -06002558
2559 // RIGHT_BRACE
2560 if (acceptTokenClass(EHTokRightBrace))
2561 return true;
2562
2563 expected(", or }");
2564 return false;
2565 } while (true);
2566}
2567
John Kessenich34fb0362016-05-03 23:17:20 -06002568// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002569// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002570//
2571// a op (b op (c op d))
2572//
2573// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002574// : initializer
2575// | conditional_expression
2576// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002577//
2578bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2579{
John Kessenich07354242016-07-01 19:58:06 -06002580 // initializer
2581 if (peekTokenClass(EHTokLeftBrace)) {
2582 if (acceptInitializer(node))
2583 return true;
2584
2585 expected("initializer");
2586 return false;
2587 }
2588
John Kessenich00957f82016-07-27 10:39:57 -06002589 // conditional_expression
2590 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002591 return false;
2592
John Kessenich07354242016-07-01 19:58:06 -06002593 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002594 TOperator assignOp = HlslOpMap::assignment(peek());
2595 if (assignOp == EOpNull)
2596 return true;
2597
John Kessenich00957f82016-07-27 10:39:57 -06002598 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002599 TSourceLoc loc = token.loc;
2600 advanceToken();
2601
John Kessenich00957f82016-07-27 10:39:57 -06002602 // conditional_expression assign_op conditional_expression ...
2603 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002604 // gets the right-to-left associativity.
2605 TIntermTyped* rightNode = nullptr;
2606 if (! acceptAssignmentExpression(rightNode)) {
2607 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002608 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002609 }
2610
John Kessenichd21baed2016-09-16 03:05:12 -06002611 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002612 node = parseContext.handleLvalue(loc, "assign", node);
2613
John Kessenichfea226b2016-07-28 17:53:56 -06002614 if (node == nullptr) {
2615 parseContext.error(loc, "could not create assignment", "", "");
2616 return false;
2617 }
John Kessenich34fb0362016-05-03 23:17:20 -06002618
2619 if (! peekTokenClass(EHTokComma))
2620 return true;
2621
2622 return true;
2623}
2624
John Kessenich00957f82016-07-27 10:39:57 -06002625// Accept a conditional expression, which associates right-to-left,
2626// accomplished by the "true" expression calling down to lower
2627// precedence levels than this level.
2628//
2629// conditional_expression
2630// : binary_expression
2631// | binary_expression QUESTION expression COLON assignment_expression
2632//
2633bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2634{
2635 // binary_expression
2636 if (! acceptBinaryExpression(node, PlLogicalOr))
2637 return false;
2638
2639 if (! acceptTokenClass(EHTokQuestion))
2640 return true;
2641
John Kessenich636b62d2017-04-11 19:45:00 -06002642 node = parseContext.convertConditionalExpression(token.loc, node, false);
John Kessenich7e997e22017-03-30 22:09:30 -06002643 if (node == nullptr)
2644 return false;
2645
John Kessenichf6deacd2017-06-06 19:52:55 -06002646 ++parseContext.controlFlowNestingLevel; // this only needs to work right if no errors
2647
John Kessenich00957f82016-07-27 10:39:57 -06002648 TIntermTyped* trueNode = nullptr;
2649 if (! acceptExpression(trueNode)) {
2650 expected("expression after ?");
2651 return false;
2652 }
2653 TSourceLoc loc = token.loc;
2654
2655 if (! acceptTokenClass(EHTokColon)) {
2656 expected(":");
2657 return false;
2658 }
2659
2660 TIntermTyped* falseNode = nullptr;
2661 if (! acceptAssignmentExpression(falseNode)) {
2662 expected("expression after :");
2663 return false;
2664 }
2665
John Kessenichf6deacd2017-06-06 19:52:55 -06002666 --parseContext.controlFlowNestingLevel;
2667
John Kessenich00957f82016-07-27 10:39:57 -06002668 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2669
2670 return true;
2671}
2672
John Kessenich34fb0362016-05-03 23:17:20 -06002673// Accept a binary expression, for binary operations that
2674// associate left-to-right. This is, it is implicit, for example
2675//
2676// ((a op b) op c) op d
2677//
2678// binary_expression
2679// : expression op expression op expression ...
2680//
2681// where 'expression' is the next higher level in precedence.
2682//
2683bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2684{
2685 if (precedenceLevel > PlMul)
2686 return acceptUnaryExpression(node);
2687
2688 // assignment_expression
2689 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2690 return false;
2691
John Kessenich34fb0362016-05-03 23:17:20 -06002692 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002693 TOperator op = HlslOpMap::binary(peek());
2694 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2695 if (tokenLevel < precedenceLevel)
2696 return true;
2697
John Kessenich34fb0362016-05-03 23:17:20 -06002698 // ... op
2699 TSourceLoc loc = token.loc;
2700 advanceToken();
2701
2702 // ... expression
2703 TIntermTyped* rightNode = nullptr;
2704 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2705 expected("expression");
2706 return false;
2707 }
2708
2709 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002710 if (node == nullptr) {
2711 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2712 return false;
2713 }
John Kessenich34fb0362016-05-03 23:17:20 -06002714 } while (true);
2715}
2716
2717// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002718// : (type) unary_expression
2719// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002720// | - unary_expression
2721// | ! unary_expression
2722// | ~ unary_expression
2723// | ++ unary_expression
2724// | -- unary_expression
2725// | postfix_expression
2726//
2727bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2728{
John Kessenich1cc1a282016-06-03 16:55:49 -06002729 // (type) unary_expression
2730 // Have to look two steps ahead, because this could be, e.g., a
2731 // postfix_expression instead, since that also starts with at "(".
2732 if (acceptTokenClass(EHTokLeftParen)) {
2733 TType castType;
2734 if (acceptType(castType)) {
John Kessenich82ae8c32017-06-13 23:13:10 -06002735 // recognize any array_specifier as part of the type
2736 TArraySizes* arraySizes = nullptr;
2737 acceptArraySpecifier(arraySizes);
2738 if (arraySizes != nullptr)
2739 castType.newArraySizes(*arraySizes);
2740 TSourceLoc loc = token.loc;
steve-lunarg5964c642016-07-30 07:38:55 -06002741 if (acceptTokenClass(EHTokRightParen)) {
2742 // We've matched "(type)" now, get the expression to cast
steve-lunarg5964c642016-07-30 07:38:55 -06002743 if (! acceptUnaryExpression(node))
2744 return false;
2745
2746 // Hook it up like a constructor
John Kessenichc633f642017-04-03 21:48:37 -06002747 TFunction* constructorFunction = parseContext.makeConstructorCall(loc, castType);
steve-lunarg5964c642016-07-30 07:38:55 -06002748 if (constructorFunction == nullptr) {
2749 expected("type that can be constructed");
2750 return false;
2751 }
2752 TIntermTyped* arguments = nullptr;
2753 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2754 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2755
2756 return true;
2757 } else {
2758 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2759 // the '(int' part. We must back up twice.
2760 recedeToken();
2761 recedeToken();
John Kessenich82ae8c32017-06-13 23:13:10 -06002762
2763 // Note, there are no array constructors like
2764 // (float[2](...))
2765 if (arraySizes != nullptr)
2766 parseContext.error(loc, "parenthesized array constructor not allowed", "([]())", "", "");
John Kessenich1cc1a282016-06-03 16:55:49 -06002767 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002768 } else {
2769 // This isn't a type cast, but it still started "(", so if it is a
2770 // unary expression, it can only be a postfix_expression, so try that.
2771 // Back it up first.
2772 recedeToken();
2773 return acceptPostfixExpression(node);
2774 }
2775 }
2776
2777 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002778 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002779
John Kessenich1cc1a282016-06-03 16:55:49 -06002780 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002781 if (unaryOp == EOpNull)
2782 return acceptPostfixExpression(node);
2783
2784 // op unary_expression
2785 TSourceLoc loc = token.loc;
2786 advanceToken();
2787 if (! acceptUnaryExpression(node))
2788 return false;
2789
2790 // + is a no-op
2791 if (unaryOp == EOpAdd)
2792 return true;
2793
2794 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002795
2796 // These unary ops require lvalues
2797 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2798 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002799
2800 return node != nullptr;
2801}
2802
2803// postfix_expression
2804// : LEFT_PAREN expression RIGHT_PAREN
2805// | literal
2806// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002807// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002808// | function_call
2809// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2810// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002811// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002812// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002813// | postfix_expression INC_OP
2814// | postfix_expression DEC_OP
2815//
2816bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2817{
2818 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002819 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002820
2821 // idToken will pick up either a variable or a function name in a function call
2822 HlslToken idToken;
2823
John Kessenich21472ae2016-06-04 11:46:33 -06002824 // Find something before the postfix operations, as they can't operate
2825 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002826 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002827 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002828 if (! acceptExpression(node)) {
2829 expected("expression");
2830 return false;
2831 }
2832 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002833 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002834 return false;
2835 }
John Kessenich34fb0362016-05-03 23:17:20 -06002836 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002837 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002838 } else if (acceptConstructor(node)) {
2839 // constructor (nothing else to do yet)
2840 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002841 // user-type, namespace name, variable, or function name
2842 TString* fullName = idToken.string;
2843 while (acceptTokenClass(EHTokColonColon)) {
2844 // user-type or namespace name
2845 fullName = NewPoolTString(fullName->c_str());
2846 fullName->append(parseContext.scopeMangler);
2847 if (acceptIdentifier(idToken))
2848 fullName->append(*idToken.string);
2849 else {
2850 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002851 return false;
2852 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002853 }
2854 if (! peekTokenClass(EHTokLeftParen)) {
2855 node = parseContext.handleVariable(idToken.loc, fullName);
2856 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002857 // function_call (nothing else to do yet)
2858 } else {
2859 expected("function call arguments");
2860 return false;
2861 }
John Kessenich21472ae2016-06-04 11:46:33 -06002862 } else {
2863 // nothing found, can't post operate
2864 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002865 }
2866
steve-lunarga2b01a02016-11-28 17:09:54 -07002867 // This is to guarantee we do this no matter how we get out of the stack frame.
2868 // This way there's no bug if an early return forgets to do it.
2869 struct tFinalize {
2870 tFinalize(HlslParseContext& p) : parseContext(p) { }
2871 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002872 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002873 private:
John Kessenichca71d942017-03-07 20:44:09 -07002874 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002875 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002876 } finalize(parseContext);
2877
2878 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2879 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2880 // level: hence the init and finalize. Even though in practice these must be
2881 // constants, they are parsed no matter what.
2882 parseContext.initFlattening();
2883
John Kessenich21472ae2016-06-04 11:46:33 -06002884 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002885 do {
2886 TSourceLoc loc = token.loc;
2887 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002888
John Kessenich34fb0362016-05-03 23:17:20 -06002889 // Consume only a valid post-unary operator, otherwise we are done.
2890 switch (postOp) {
2891 case EOpIndexDirectStruct:
2892 case EOpIndexIndirect:
2893 case EOpPostIncrement:
2894 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002895 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002896 advanceToken();
2897 break;
2898 default:
2899 return true;
2900 }
John Kessenich87142c72016-03-12 20:24:24 -07002901
John Kessenich34fb0362016-05-03 23:17:20 -06002902 // We have a valid post-unary operator, process it.
2903 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002904 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002905 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002906 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002907 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002908 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002909 HlslToken field;
2910 if (! acceptIdentifier(field)) {
2911 expected("swizzle or member");
2912 return false;
2913 }
LoopDawg4886f692016-06-29 10:58:58 -06002914
John Kessenich516d92d2017-03-08 20:09:03 -07002915 if (peekTokenClass(EHTokLeftParen)) {
2916 // member function
2917 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002918
John Kessenich516d92d2017-03-08 20:09:03 -07002919 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002920 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002921 expected("function parameters");
2922 return false;
2923 }
John Kessenich516d92d2017-03-08 20:09:03 -07002924 } else
2925 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002926
John Kessenich34fb0362016-05-03 23:17:20 -06002927 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002928 }
John Kessenich34fb0362016-05-03 23:17:20 -06002929 case EOpIndexIndirect:
2930 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002931 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002932 TIntermTyped* indexNode = nullptr;
2933 if (! acceptExpression(indexNode) ||
2934 ! peekTokenClass(EHTokRightBracket)) {
2935 expected("expression followed by ']'");
2936 return false;
2937 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002938 advanceToken();
2939 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
steve-lunarg2efd6c62017-04-06 20:22:20 -06002940 if (node == nullptr)
2941 return false;
John Kessenich19b92ff2016-06-19 11:50:34 -06002942 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002943 }
2944 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002945 // INC_OP
2946 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002947 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002948 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002949 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002950 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002951 break;
2952 default:
2953 assert(0);
2954 break;
2955 }
2956 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002957}
2958
John Kessenichd016be12016-03-13 11:24:20 -06002959// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002960// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002961//
2962bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2963{
2964 // type
2965 TType type;
2966 if (acceptType(type)) {
John Kessenichc633f642017-04-03 21:48:37 -06002967 TFunction* constructorFunction = parseContext.makeConstructorCall(token.loc, type);
John Kessenichd016be12016-03-13 11:24:20 -06002968 if (constructorFunction == nullptr)
2969 return false;
2970
2971 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002972 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002973 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002974 // It's possible this is a type keyword used as an identifier. Put the token back
2975 // for later use.
2976 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002977 return false;
2978 }
2979
2980 // hook it up
2981 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2982
2983 return true;
2984 }
2985
2986 return false;
2987}
2988
John Kessenich34fb0362016-05-03 23:17:20 -06002989// The function_call identifier was already recognized, and passed in as idToken.
2990//
2991// function_call
2992// : [idToken] arguments
2993//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002994bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002995{
John Kessenich54ee28f2017-03-11 14:13:00 -07002996 // name
2997 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002998 if (baseObject == nullptr) {
2999 functionName = &name;
3000 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06003001 // Built-in methods are not in the symbol table as methods, but as global functions
3002 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06003003 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06003004 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06003005 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06003006 if (! baseObject->getType().isStruct()) {
3007 expected("structure");
3008 return false;
3009 }
John Kessenich54ee28f2017-03-11 14:13:00 -07003010 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06003011 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06003012 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06003013 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07003014 }
LoopDawg4886f692016-06-29 10:58:58 -06003015
John Kessenich54ee28f2017-03-11 14:13:00 -07003016 // function
3017 TFunction* function = new TFunction(functionName, TType(EbtVoid));
3018
3019 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07003020 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06003021 if (baseObject != nullptr) {
3022 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07003023 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06003024 }
John Kessenich4678ca92016-05-13 09:33:42 -06003025 if (! acceptArguments(function, arguments))
3026 return false;
3027
John Kessenich54ee28f2017-03-11 14:13:00 -07003028 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06003029 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06003030
3031 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06003032}
3033
John Kessenich87142c72016-03-12 20:24:24 -07003034// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06003035// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07003036//
John Kessenichd016be12016-03-13 11:24:20 -06003037// The arguments are pushed onto the 'function' argument list and
3038// onto the 'arguments' aggregate.
3039//
John Kessenich4678ca92016-05-13 09:33:42 -06003040bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07003041{
John Kessenich078d7f22016-03-14 10:02:11 -06003042 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07003043 if (! acceptTokenClass(EHTokLeftParen))
3044 return false;
3045
John Kessenich2aa12b12017-04-18 14:47:33 -06003046 // RIGHT_PAREN
3047 if (acceptTokenClass(EHTokRightParen))
3048 return true;
3049
3050 // must now be at least one expression...
John Kessenich87142c72016-03-12 20:24:24 -07003051 do {
John Kessenichd016be12016-03-13 11:24:20 -06003052 // expression
John Kessenich87142c72016-03-12 20:24:24 -07003053 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06003054 if (! acceptAssignmentExpression(arg))
John Kessenich2aa12b12017-04-18 14:47:33 -06003055 return false;
John Kessenichd016be12016-03-13 11:24:20 -06003056
3057 // hook it up
3058 parseContext.handleFunctionArgument(function, arguments, arg);
3059
John Kessenich078d7f22016-03-14 10:02:11 -06003060 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07003061 if (! acceptTokenClass(EHTokComma))
3062 break;
3063 } while (true);
3064
John Kessenich078d7f22016-03-14 10:02:11 -06003065 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07003066 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003067 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07003068 return false;
3069 }
3070
3071 return true;
3072}
3073
3074bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
3075{
3076 switch (token.tokenClass) {
3077 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003078 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003079 break;
steve-lunarg2de32912016-07-28 14:49:48 -06003080 case EHTokUintConstant:
3081 node = intermediate.addConstantUnion(token.u, token.loc, true);
3082 break;
John Kessenich87142c72016-03-12 20:24:24 -07003083 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003084 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003085 break;
3086 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003087 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003088 break;
3089 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06003090 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07003091 break;
John Kessenich86f71382016-09-19 20:23:18 -06003092 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07003093 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06003094 break;
John Kessenich87142c72016-03-12 20:24:24 -07003095
3096 default:
3097 return false;
3098 }
3099
3100 advanceToken();
3101
3102 return true;
3103}
3104
John Kessenich0e071192017-06-06 11:37:33 -06003105// simple_statement
3106// : SEMICOLON
3107// | declaration_statement
3108// | expression SEMICOLON
3109//
3110bool HlslGrammar::acceptSimpleStatement(TIntermNode*& statement)
3111{
3112 // SEMICOLON
3113 if (acceptTokenClass(EHTokSemicolon))
3114 return true;
3115
3116 // declaration
3117 if (acceptDeclaration(statement))
3118 return true;
3119
3120 // expression
3121 TIntermTyped* node;
3122 if (acceptExpression(node))
3123 statement = node;
3124 else
3125 return false;
3126
3127 // SEMICOLON (following an expression)
3128 if (acceptTokenClass(EHTokSemicolon))
3129 return true;
3130 else {
3131 expected(";");
3132 return false;
3133 }
3134}
3135
John Kessenich5f934b02016-03-13 17:58:25 -06003136// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06003137// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003138//
John Kessenich21472ae2016-06-04 11:46:33 -06003139bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07003140{
John Kessenich21472ae2016-06-04 11:46:33 -06003141 TIntermAggregate* compoundStatement = nullptr;
3142
John Kessenich34fb0362016-05-03 23:17:20 -06003143 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003144 if (! acceptTokenClass(EHTokLeftBrace))
3145 return false;
3146
3147 // statement statement ...
3148 TIntermNode* statement = nullptr;
3149 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06003150 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
3151 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
3152 branch->getFlowOp() == EOpDefault)) {
3153 // hook up individual subsequences within a switch statement
3154 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
3155 compoundStatement = nullptr;
3156 } else {
3157 // hook it up to the growing compound statement
3158 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
3159 }
John Kessenich5f934b02016-03-13 17:58:25 -06003160 }
John Kessenich34fb0362016-05-03 23:17:20 -06003161 if (compoundStatement)
3162 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06003163
John Kessenich21472ae2016-06-04 11:46:33 -06003164 retStatement = compoundStatement;
3165
John Kessenich34fb0362016-05-03 23:17:20 -06003166 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003167 return acceptTokenClass(EHTokRightBrace);
3168}
3169
John Kessenich0d2b6de2016-06-05 11:23:11 -06003170bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3171{
3172 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003173 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003174 parseContext.popScope();
3175
3176 return result;
3177}
3178
John Kessenich077e0522016-06-09 02:02:17 -06003179bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003180{
John Kessenich077e0522016-06-09 02:02:17 -06003181 parseContext.pushScope();
3182 bool result = acceptCompoundStatement(statement);
3183 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003184
3185 return result;
3186}
3187
John Kessenich5f934b02016-03-13 17:58:25 -06003188// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003189// : attributes attributed_statement
3190//
3191// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003192// : compound_statement
John Kessenich0e071192017-06-06 11:37:33 -06003193// | simple_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003194// | selection_statement
3195// | switch_statement
3196// | case_label
John Kessenich0e071192017-06-06 11:37:33 -06003197// | default_label
John Kessenich21472ae2016-06-04 11:46:33 -06003198// | iteration_statement
3199// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003200//
3201bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3202{
John Kessenich21472ae2016-06-04 11:46:33 -06003203 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003204
John Kessenich21472ae2016-06-04 11:46:33 -06003205 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003206 TAttributeMap attributes;
3207 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003208
John Kessenich21472ae2016-06-04 11:46:33 -06003209 // attributed_statement
3210 switch (peek()) {
3211 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003212 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003213
John Kessenich21472ae2016-06-04 11:46:33 -06003214 case EHTokIf:
3215 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003216
John Kessenich21472ae2016-06-04 11:46:33 -06003217 case EHTokSwitch:
3218 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003219
John Kessenich21472ae2016-06-04 11:46:33 -06003220 case EHTokFor:
3221 case EHTokDo:
3222 case EHTokWhile:
steve-lunargf1709e72017-05-02 20:14:50 -06003223 return acceptIterationStatement(statement, attributes);
John Kessenich21472ae2016-06-04 11:46:33 -06003224
3225 case EHTokContinue:
3226 case EHTokBreak:
3227 case EHTokDiscard:
3228 case EHTokReturn:
3229 return acceptJumpStatement(statement);
3230
3231 case EHTokCase:
3232 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003233 case EHTokDefault:
3234 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003235
John Kessenich21472ae2016-06-04 11:46:33 -06003236 case EHTokRightBrace:
3237 // Performance: not strictly necessary, but stops a bunch of hunting early,
3238 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003239 return false;
3240
John Kessenich21472ae2016-06-04 11:46:33 -06003241 default:
John Kessenich0e071192017-06-06 11:37:33 -06003242 return acceptSimpleStatement(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003243 }
3244
John Kessenich5f934b02016-03-13 17:58:25 -06003245 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003246}
3247
John Kessenich21472ae2016-06-04 11:46:33 -06003248// attributes
3249// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3250//
3251// attribute:
3252// : UNROLL
3253// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3254// | FASTOPT
3255// | ALLOW_UAV_CONDITION
3256// | BRANCH
3257// | FLATTEN
3258// | FORCECASE
3259// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003260// | DOMAIN
3261// | EARLYDEPTHSTENCIL
3262// | INSTANCE
3263// | MAXTESSFACTOR
3264// | OUTPUTCONTROLPOINTS
3265// | OUTPUTTOPOLOGY
3266// | PARTITIONING
3267// | PATCHCONSTANTFUNC
3268// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003269//
steve-lunarg1868b142016-10-20 13:07:10 -06003270void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003271{
steve-lunarg1868b142016-10-20 13:07:10 -06003272 // For now, accept the [ XXX(X) ] syntax, but drop all but
3273 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003274 // TODO: subset to correct set? Pass on?
3275 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003276 HlslToken idToken;
3277
John Kessenich0d2b6de2016-06-05 11:23:11 -06003278 // LEFT_BRACKET?
3279 if (! acceptTokenClass(EHTokLeftBracket))
3280 return;
3281
3282 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003283 if (acceptIdentifier(idToken)) {
3284 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003285 } else if (! peekTokenClass(EHTokRightBracket)) {
3286 expected("identifier");
3287 advanceToken();
3288 }
3289
steve-lunarga22f7db2016-11-11 08:17:44 -07003290 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003291
3292 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003293 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003294 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003295
John Kessenich0d2b6de2016-06-05 11:23:11 -06003296 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003297 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003298
steve-lunarga22f7db2016-11-11 08:17:44 -07003299 while (acceptAssignmentExpression(node)) {
3300 expectingExpression = false;
3301 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003302 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003303 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003304 }
3305
steve-lunarga22f7db2016-11-11 08:17:44 -07003306 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003307 if (! acceptTokenClass(EHTokRightParen))
3308 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003309
3310 // Error for partial or missing expression
3311 if (expectingExpression || expressions->getSequence().empty())
3312 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003313 }
3314
3315 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003316 if (!acceptTokenClass(EHTokRightBracket)) {
3317 expected("]");
3318 return;
3319 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003320
steve-lunarg1868b142016-10-20 13:07:10 -06003321 // Add any values we found into the attribute map. This accepts
3322 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003323 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003324 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003325}
3326
John Kessenich0d2b6de2016-06-05 11:23:11 -06003327// selection_statement
3328// : IF LEFT_PAREN expression RIGHT_PAREN statement
3329// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3330//
John Kessenich21472ae2016-06-04 11:46:33 -06003331bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3332{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003333 TSourceLoc loc = token.loc;
3334
3335 // IF
3336 if (! acceptTokenClass(EHTokIf))
3337 return false;
3338
3339 // so that something declared in the condition is scoped to the lifetimes
3340 // of the then-else statements
3341 parseContext.pushScope();
3342
3343 // LEFT_PAREN expression RIGHT_PAREN
3344 TIntermTyped* condition;
3345 if (! acceptParenExpression(condition))
3346 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003347 condition = parseContext.convertConditionalExpression(loc, condition);
3348 if (condition == nullptr)
3349 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003350
3351 // create the child statements
3352 TIntermNodePair thenElse = { nullptr, nullptr };
3353
John Kessenichf6deacd2017-06-06 19:52:55 -06003354 ++parseContext.controlFlowNestingLevel; // this only needs to work right if no errors
3355
John Kessenich0d2b6de2016-06-05 11:23:11 -06003356 // then statement
3357 if (! acceptScopedStatement(thenElse.node1)) {
3358 expected("then statement");
3359 return false;
3360 }
3361
3362 // ELSE
3363 if (acceptTokenClass(EHTokElse)) {
3364 // else statement
3365 if (! acceptScopedStatement(thenElse.node2)) {
3366 expected("else statement");
3367 return false;
3368 }
3369 }
3370
3371 // Put the pieces together
3372 statement = intermediate.addSelection(condition, thenElse, loc);
3373 parseContext.popScope();
John Kessenichf6deacd2017-06-06 19:52:55 -06003374 --parseContext.controlFlowNestingLevel;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003375
3376 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003377}
3378
John Kessenichd02dc5d2016-07-01 00:04:11 -06003379// switch_statement
3380// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3381//
John Kessenich21472ae2016-06-04 11:46:33 -06003382bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3383{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003384 // SWITCH
3385 TSourceLoc loc = token.loc;
3386 if (! acceptTokenClass(EHTokSwitch))
3387 return false;
3388
3389 // LEFT_PAREN expression RIGHT_PAREN
3390 parseContext.pushScope();
3391 TIntermTyped* switchExpression;
3392 if (! acceptParenExpression(switchExpression)) {
3393 parseContext.popScope();
3394 return false;
3395 }
3396
3397 // compound_statement
3398 parseContext.pushSwitchSequence(new TIntermSequence);
John Kessenichf6deacd2017-06-06 19:52:55 -06003399
3400 ++parseContext.controlFlowNestingLevel;
John Kessenichd02dc5d2016-07-01 00:04:11 -06003401 bool statementOkay = acceptCompoundStatement(statement);
John Kessenichf6deacd2017-06-06 19:52:55 -06003402 --parseContext.controlFlowNestingLevel;
3403
John Kessenichd02dc5d2016-07-01 00:04:11 -06003404 if (statementOkay)
3405 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3406
3407 parseContext.popSwitchSequence();
3408 parseContext.popScope();
3409
3410 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003411}
3412
John Kessenich119f8f62016-06-05 15:44:07 -06003413// iteration_statement
3414// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3415// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3416// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3417//
3418// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
steve-lunargf1709e72017-05-02 20:14:50 -06003419bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003420{
John Kessenich119f8f62016-06-05 15:44:07 -06003421 TSourceLoc loc = token.loc;
3422 TIntermTyped* condition = nullptr;
3423
3424 EHlslTokenClass loop = peek();
3425 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3426
3427 // WHILE or DO or FOR
3428 advanceToken();
steve-lunargf1709e72017-05-02 20:14:50 -06003429
3430 const TLoopControl control = parseContext.handleLoopControl(attributes);
John Kessenich119f8f62016-06-05 15:44:07 -06003431
3432 switch (loop) {
3433 case EHTokWhile:
3434 // so that something declared in the condition is scoped to the lifetime
3435 // of the while sub-statement
John Kessenichf6deacd2017-06-06 19:52:55 -06003436 parseContext.pushScope(); // this only needs to work right if no errors
John Kessenich119f8f62016-06-05 15:44:07 -06003437 parseContext.nestLooping();
John Kessenichf6deacd2017-06-06 19:52:55 -06003438 ++parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003439
3440 // LEFT_PAREN condition RIGHT_PAREN
3441 if (! acceptParenExpression(condition))
3442 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003443 condition = parseContext.convertConditionalExpression(loc, condition);
3444 if (condition == nullptr)
3445 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003446
3447 // statement
3448 if (! acceptScopedStatement(statement)) {
3449 expected("while sub-statement");
3450 return false;
3451 }
3452
3453 parseContext.unnestLooping();
3454 parseContext.popScope();
John Kessenichf6deacd2017-06-06 19:52:55 -06003455 --parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003456
steve-lunargf1709e72017-05-02 20:14:50 -06003457 statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003458
3459 return true;
3460
3461 case EHTokDo:
John Kessenichf6deacd2017-06-06 19:52:55 -06003462 parseContext.nestLooping(); // this only needs to work right if no errors
3463 ++parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003464
John Kessenich119f8f62016-06-05 15:44:07 -06003465 // statement
John Kessenich0c6f9362017-04-20 11:08:24 -06003466 if (! acceptScopedStatement(statement)) {
John Kessenich119f8f62016-06-05 15:44:07 -06003467 expected("do sub-statement");
3468 return false;
3469 }
3470
John Kessenich119f8f62016-06-05 15:44:07 -06003471 // WHILE
3472 if (! acceptTokenClass(EHTokWhile)) {
3473 expected("while");
3474 return false;
3475 }
3476
3477 // LEFT_PAREN condition RIGHT_PAREN
3478 TIntermTyped* condition;
3479 if (! acceptParenExpression(condition))
3480 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003481 condition = parseContext.convertConditionalExpression(loc, condition);
3482 if (condition == nullptr)
3483 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003484
3485 if (! acceptTokenClass(EHTokSemicolon))
3486 expected(";");
3487
3488 parseContext.unnestLooping();
John Kessenichf6deacd2017-06-06 19:52:55 -06003489 --parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003490
steve-lunargf1709e72017-05-02 20:14:50 -06003491 statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003492
3493 return true;
3494
3495 case EHTokFor:
3496 {
3497 // LEFT_PAREN
3498 if (! acceptTokenClass(EHTokLeftParen))
3499 expected("(");
3500
3501 // so that something declared in the condition is scoped to the lifetime
3502 // of the for sub-statement
3503 parseContext.pushScope();
3504
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003505 // initializer
3506 TIntermNode* initNode = nullptr;
John Kessenich0e071192017-06-06 11:37:33 -06003507 if (! acceptSimpleStatement(initNode))
3508 expected("for-loop initializer statement");
John Kessenich119f8f62016-06-05 15:44:07 -06003509
John Kessenichf6deacd2017-06-06 19:52:55 -06003510 parseContext.nestLooping(); // this only needs to work right if no errors
3511 ++parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003512
3513 // condition SEMI_COLON
3514 acceptExpression(condition);
3515 if (! acceptTokenClass(EHTokSemicolon))
3516 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003517 if (condition != nullptr) {
3518 condition = parseContext.convertConditionalExpression(loc, condition);
3519 if (condition == nullptr)
3520 return false;
3521 }
John Kessenich119f8f62016-06-05 15:44:07 -06003522
3523 // iterator SEMI_COLON
3524 TIntermTyped* iterator = nullptr;
3525 acceptExpression(iterator);
3526 if (! acceptTokenClass(EHTokRightParen))
3527 expected(")");
3528
3529 // statement
3530 if (! acceptScopedStatement(statement)) {
3531 expected("for sub-statement");
3532 return false;
3533 }
3534
steve-lunargf1709e72017-05-02 20:14:50 -06003535 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
John Kessenich119f8f62016-06-05 15:44:07 -06003536
3537 parseContext.popScope();
3538 parseContext.unnestLooping();
John Kessenichf6deacd2017-06-06 19:52:55 -06003539 --parseContext.controlFlowNestingLevel;
John Kessenich119f8f62016-06-05 15:44:07 -06003540
3541 return true;
3542 }
3543
3544 default:
3545 return false;
3546 }
John Kessenich21472ae2016-06-04 11:46:33 -06003547}
3548
3549// jump_statement
3550// : CONTINUE SEMICOLON
3551// | BREAK SEMICOLON
3552// | DISCARD SEMICOLON
3553// | RETURN SEMICOLON
3554// | RETURN expression SEMICOLON
3555//
3556bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3557{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003558 EHlslTokenClass jump = peek();
3559 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003560 case EHTokContinue:
3561 case EHTokBreak:
3562 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003563 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003564 advanceToken();
3565 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003566 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003567 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003568 return false;
3569 }
John Kessenich21472ae2016-06-04 11:46:33 -06003570
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003571 switch (jump) {
3572 case EHTokContinue:
3573 statement = intermediate.addBranch(EOpContinue, token.loc);
3574 break;
3575 case EHTokBreak:
3576 statement = intermediate.addBranch(EOpBreak, token.loc);
3577 break;
3578 case EHTokDiscard:
3579 statement = intermediate.addBranch(EOpKill, token.loc);
3580 break;
3581
3582 case EHTokReturn:
3583 {
3584 // expression
3585 TIntermTyped* node;
3586 if (acceptExpression(node)) {
3587 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003588 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003589 } else
3590 statement = intermediate.addBranch(EOpReturn, token.loc);
3591 break;
3592 }
3593
3594 default:
3595 assert(0);
3596 return false;
3597 }
3598
3599 // SEMICOLON
3600 if (! acceptTokenClass(EHTokSemicolon))
3601 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003602
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003603 return true;
3604}
John Kessenich21472ae2016-06-04 11:46:33 -06003605
John Kessenichd02dc5d2016-07-01 00:04:11 -06003606// case_label
3607// : CASE expression COLON
3608//
John Kessenich21472ae2016-06-04 11:46:33 -06003609bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3610{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003611 TSourceLoc loc = token.loc;
3612 if (! acceptTokenClass(EHTokCase))
3613 return false;
3614
3615 TIntermTyped* expression;
3616 if (! acceptExpression(expression)) {
3617 expected("case expression");
3618 return false;
3619 }
3620
3621 if (! acceptTokenClass(EHTokColon)) {
3622 expected(":");
3623 return false;
3624 }
3625
3626 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3627
3628 return true;
3629}
3630
3631// default_label
3632// : DEFAULT COLON
3633//
3634bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3635{
3636 TSourceLoc loc = token.loc;
3637 if (! acceptTokenClass(EHTokDefault))
3638 return false;
3639
3640 if (! acceptTokenClass(EHTokColon)) {
3641 expected(":");
3642 return false;
3643 }
3644
3645 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3646
3647 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003648}
3649
John Kessenich19b92ff2016-06-19 11:50:34 -06003650// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003651// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3652// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003653//
3654void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3655{
3656 arraySizes = nullptr;
3657
steve-lunarg7b211a32016-10-13 12:26:18 -06003658 // Early-out if there aren't any array dimensions
3659 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003660 return;
3661
steve-lunarg7b211a32016-10-13 12:26:18 -06003662 // 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 -06003663 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003664
3665 // Collect each array dimension.
3666 while (acceptTokenClass(EHTokLeftBracket)) {
3667 TSourceLoc loc = token.loc;
3668 TIntermTyped* sizeExpr = nullptr;
3669
John Kessenich057df292017-03-06 18:18:37 -07003670 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003671 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3672
3673 if (! acceptTokenClass(EHTokRightBracket)) {
3674 expected("]");
3675 return;
3676 }
3677
3678 if (hasArraySize) {
3679 TArraySize arraySize;
3680 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3681 arraySizes->addInnerSize(arraySize);
3682 } else {
3683 arraySizes->addInnerSize(0); // sized by initializers.
3684 }
steve-lunarg265c0612016-09-27 10:57:35 -06003685 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003686}
3687
John Kessenich630dd7d2016-06-12 23:52:12 -06003688// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003689// : COLON semantic // optional
3690// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3691// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003692// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003693// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003694//
John Kessenich854fe242017-03-02 14:30:59 -07003695// Return true if any tokens were accepted. That is,
3696// false can be returned on successfully recognizing nothing,
3697// not necessarily meaning bad syntax.
3698//
3699bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003700{
John Kessenich854fe242017-03-02 14:30:59 -07003701 bool found = false;
3702
John Kessenich630dd7d2016-06-12 23:52:12 -06003703 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003704 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003705 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003706 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003707 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003708 if (peekTokenClass(EHTokLayout))
3709 acceptLayoutQualifierList(qualifier);
3710 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003711 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003712 if (! acceptTokenClass(EHTokLeftParen)) {
3713 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003714 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003715 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003716 HlslToken locationToken;
3717 if (! acceptIdentifier(locationToken)) {
3718 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003719 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003720 }
3721 HlslToken componentToken;
3722 if (acceptTokenClass(EHTokDot)) {
3723 if (! acceptIdentifier(componentToken)) {
3724 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003725 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003726 }
3727 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003728 if (! acceptTokenClass(EHTokRightParen)) {
3729 expected(")");
3730 break;
3731 }
John Kessenich7735b942016-09-05 12:40:06 -06003732 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003733 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003734 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003735 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003736 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003737 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3738 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003739 if (! acceptTokenClass(EHTokLeftParen)) {
3740 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003741 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003742 }
John Kessenichb38f0712016-07-30 10:29:54 -06003743 HlslToken registerDesc; // for Type#
3744 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003745 if (! acceptIdentifier(registerDesc)) {
3746 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003747 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003748 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003749 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3750 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003751 // Then we didn't really see the registerDesc yet, it was
3752 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003753 profile = registerDesc;
3754 if (! acceptIdentifier(registerDesc)) {
3755 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003756 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003757 }
3758 }
John Kessenichb38f0712016-07-30 10:29:54 -06003759 int subComponent = 0;
3760 if (acceptTokenClass(EHTokLeftBracket)) {
3761 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3762 if (! peekTokenClass(EHTokIntConstant)) {
3763 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003764 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003765 }
3766 subComponent = token.i;
3767 advanceToken();
3768 if (! acceptTokenClass(EHTokRightBracket)) {
3769 expected("]");
3770 break;
3771 }
3772 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003773 // (COMMA SPACEN)opt
3774 HlslToken spaceDesc;
3775 if (acceptTokenClass(EHTokComma)) {
3776 if (! acceptIdentifier(spaceDesc)) {
3777 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003778 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003779 }
3780 }
3781 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003782 if (! acceptTokenClass(EHTokRightParen)) {
3783 expected(")");
3784 break;
3785 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003786 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003787 } else {
3788 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003789 TString semanticUpperCase = *idToken.string;
3790 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3791 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003792 }
John Kessenich854fe242017-03-02 14:30:59 -07003793 } else if (peekTokenClass(EHTokLeftAngle)) {
3794 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003795 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003796 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003797 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003798
John Kessenich630dd7d2016-06-12 23:52:12 -06003799 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003800
3801 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003802}
3803
John Kessenichb16f7e62017-03-11 19:32:47 -07003804//
3805// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3806// processing.
3807//
3808bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3809{
3810 if (! peekTokenClass(EHTokLeftBrace))
3811 return false;
3812
3813 int braceCount = 0;
3814
3815 do {
3816 switch (peek()) {
3817 case EHTokLeftBrace:
3818 ++braceCount;
3819 break;
3820 case EHTokRightBrace:
3821 --braceCount;
3822 break;
3823 case EHTokNone:
3824 // End of input before balance { } is bad...
3825 return false;
3826 default:
3827 break;
3828 }
3829
3830 tokens.push_back(token);
3831 advanceToken();
3832 } while (braceCount > 0);
3833
3834 return true;
3835}
3836
John Kessenich0320d092017-06-13 22:22:52 -06003837// Return a string for just the types that can also be declared as an identifier.
3838const char* HlslGrammar::getTypeString(EHlslTokenClass tokenClass) const
3839{
3840 switch (tokenClass) {
3841 case EHTokSample: return "sample";
3842 case EHTokHalf: return "half";
3843 case EHTokHalf1x1: return "half1x1";
3844 case EHTokHalf1x2: return "half1x2";
3845 case EHTokHalf1x3: return "half1x3";
3846 case EHTokHalf1x4: return "half1x4";
3847 case EHTokHalf2x1: return "half2x1";
3848 case EHTokHalf2x2: return "half2x2";
3849 case EHTokHalf2x3: return "half2x3";
3850 case EHTokHalf2x4: return "half2x4";
3851 case EHTokHalf3x1: return "half3x1";
3852 case EHTokHalf3x2: return "half3x2";
3853 case EHTokHalf3x3: return "half3x3";
3854 case EHTokHalf3x4: return "half3x4";
3855 case EHTokHalf4x1: return "half4x1";
3856 case EHTokHalf4x2: return "half4x2";
3857 case EHTokHalf4x3: return "half4x3";
3858 case EHTokHalf4x4: return "half4x4";
3859 case EHTokBool: return "bool";
3860 case EHTokFloat: return "float";
3861 case EHTokDouble: return "double";
3862 case EHTokInt: return "int";
3863 case EHTokUint: return "uint";
3864 case EHTokMin16float: return "min16float";
3865 case EHTokMin10float: return "min10float";
3866 case EHTokMin16int: return "min16int";
3867 case EHTokMin12int: return "min12int";
3868 default:
3869 return nullptr;
3870 }
3871}
3872
John Kesseniche01a9bc2016-03-12 20:11:22 -07003873} // end namespace glslang