blob: b764d89029a4299b40ed20156955c23750ad2b7b [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2016 Google, Inc.
3// Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kesseniche01a9bc2016-03-12 20:11:22 -07006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kesseniche01a9bc2016-03-12 20:11:22 -070010//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of Google, Inc., nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
John Kessenich927608b2017-01-06 12:34:14 -070023// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
John Kesseniche01a9bc2016-03-12 20:11:22 -070035//
36
John Kessenichd016be12016-03-13 11:24:20 -060037//
38// This is a set of mutually recursive methods implementing the HLSL grammar.
39// Generally, each returns
40// - through an argument: a type specifically appropriate to which rule it
41// recognized
42// - through the return value: true/false to indicate whether or not it
43// recognized its rule
44//
45// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060046// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060047// will build the AST.
48//
49// The next token, yet to be "accepted" is always sitting in 'token'.
50// When a method says it accepts a rule, that means all tokens involved
51// in the rule will have been consumed, and none left in 'token'.
52//
53
John Kesseniche01a9bc2016-03-12 20:11:22 -070054#include "hlslTokens.h"
55#include "hlslGrammar.h"
steve-lunarg1868b142016-10-20 13:07:10 -060056#include "hlslAttributes.h"
John Kesseniche01a9bc2016-03-12 20:11:22 -070057
58namespace glslang {
59
60// Root entry point to this recursive decent parser.
61// Return true if compilation unit was successfully accepted.
62bool HlslGrammar::parse()
63{
64 advanceToken();
65 return acceptCompilationUnit();
66}
67
68void HlslGrammar::expected(const char* syntax)
69{
70 parseContext.error(token.loc, "Expected", syntax, "");
71}
72
LoopDawg4886f692016-06-29 10:58:58 -060073void HlslGrammar::unimplemented(const char* error)
74{
75 parseContext.error(token.loc, "Unimplemented", error, "");
76}
77
John Kessenich7a41f962017-03-22 11:38:22 -060078// IDENTIFIER
79// THIS
80// type that can be used as IDENTIFIER
81//
John Kessenichaecd4972016-03-14 10:46:34 -060082// Only process the next token if it is an identifier.
83// Return true if it was an identifier.
84bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
85{
John Kessenich7a41f962017-03-22 11:38:22 -060086 // IDENTIFIER
John Kessenichaecd4972016-03-14 10:46:34 -060087 if (peekTokenClass(EHTokIdentifier)) {
88 idToken = token;
89 advanceToken();
90 return true;
91 }
92
John Kessenich7a41f962017-03-22 11:38:22 -060093 // THIS
94 // -> maps to the IDENTIFIER spelled with the internal special name for 'this'
95 if (peekTokenClass(EHTokThis)) {
96 idToken = token;
97 advanceToken();
98 idToken.tokenClass = EHTokIdentifier;
99 idToken.string = NewPoolTString(intermediate.implicitThisName);
100 return true;
101 }
102
103 // type that can be used as IDENTIFIER
104
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700105 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
106 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
107 // valid identifier, nor is "linear". This code special cases the known instances of this, so
108 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
John Kessenichecba76f2017-01-06 00:34:48 -0700109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 TString* idString = nullptr;
111 switch (peek()) {
112 case EHTokSample: idString = NewPoolTString("sample"); break;
113 case EHTokHalf: idString = NewPoolTString("half"); break;
114 case EHTokBool: idString = NewPoolTString("bool"); break;
115 case EHTokFloat: idString = NewPoolTString("float"); break;
116 case EHTokDouble: idString = NewPoolTString("double"); break;
117 case EHTokInt: idString = NewPoolTString("int"); break;
118 case EHTokUint: idString = NewPoolTString("uint"); break;
119 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
120 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
121 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
122 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
123 default:
124 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700125 }
126
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700127 token.string = idString;
128 token.tokenClass = EHTokIdentifier;
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700129 idToken = token;
130
131 advanceToken();
132
133 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600134}
135
John Kesseniche01a9bc2016-03-12 20:11:22 -0700136// compilationUnit
John Kessenich8f9fdc92017-03-30 16:22:26 -0600137// : declaration_list EOF
John Kesseniche01a9bc2016-03-12 20:11:22 -0700138//
139bool HlslGrammar::acceptCompilationUnit()
140{
John Kessenichd016be12016-03-13 11:24:20 -0600141 TIntermNode* unitNode = nullptr;
142
John Kessenich8f9fdc92017-03-30 16:22:26 -0600143 if (! acceptDeclarationList(unitNode))
144 return false;
steve-lunargcb88de52016-08-03 07:04:18 -0600145
John Kessenich8f9fdc92017-03-30 16:22:26 -0600146 if (! peekTokenClass(EHTokNone))
147 return false;
John Kesseniche01a9bc2016-03-12 20:11:22 -0700148
John Kessenichd016be12016-03-13 11:24:20 -0600149 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700150 if (unitNode && !unitNode->getAsAggregate())
151 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600152 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600153
John Kesseniche01a9bc2016-03-12 20:11:22 -0700154 return true;
155}
156
John Kessenich8f9fdc92017-03-30 16:22:26 -0600157// Recognize the following, but with the extra condition that it can be
158// successfully terminated by EOF or '}'.
159//
160// declaration_list
161// : list of declaration_or_semicolon followed by EOF or RIGHT_BRACE
162//
163// declaration_or_semicolon
164// : declaration
165// : SEMICOLON
166//
167bool HlslGrammar::acceptDeclarationList(TIntermNode*& nodeList)
168{
169 do {
170 // HLSL allows extra semicolons between global declarations
171 do { } while (acceptTokenClass(EHTokSemicolon));
172
173 // EOF or RIGHT_BRACE
174 if (peekTokenClass(EHTokNone) || peekTokenClass(EHTokRightBrace))
175 return true;
176
177 // declaration
178 if (! acceptDeclaration(nodeList))
179 return false;
180 } while (true);
181
182 return true;
183}
184
LoopDawg4886f692016-06-29 10:58:58 -0600185// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700186// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600187//
188// sampler_state_assignment
189// : sampler_state_identifier EQUAL value SEMICOLON
190//
191// sampler_state_identifier
192// : ADDRESSU
193// | ADDRESSV
194// | ADDRESSW
195// | BORDERCOLOR
196// | FILTER
197// | MAXANISOTROPY
198// | MAXLOD
199// | MINLOD
200// | MIPLODBIAS
201//
202bool HlslGrammar::acceptSamplerState()
203{
204 // TODO: this should be genericized to accept a list of valid tokens and
205 // return token/value pairs. Presently it is specific to texture values.
206
207 if (! acceptTokenClass(EHTokLeftBrace))
208 return true;
209
210 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700211
LoopDawg4886f692016-06-29 10:58:58 -0600212 do {
213 // read state name
214 HlslToken state;
215 if (! acceptIdentifier(state))
216 break; // end of list
217
218 // FXC accepts any case
219 TString stateName = *state.string;
220 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
221
222 if (! acceptTokenClass(EHTokAssign)) {
223 expected("assign");
224 return false;
225 }
226
227 if (stateName == "minlod" || stateName == "maxlod") {
228 if (! peekTokenClass(EHTokIntConstant)) {
229 expected("integer");
230 return false;
231 }
232
233 TIntermTyped* lod = nullptr;
234 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
235 return false;
236 } else if (stateName == "maxanisotropy") {
237 if (! peekTokenClass(EHTokIntConstant)) {
238 expected("integer");
239 return false;
240 }
241
242 TIntermTyped* maxAnisotropy = nullptr;
243 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
244 return false;
245 } else if (stateName == "filter") {
246 HlslToken filterMode;
247 if (! acceptIdentifier(filterMode)) {
248 expected("filter mode");
249 return false;
250 }
251 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
252 HlslToken addrMode;
253 if (! acceptIdentifier(addrMode)) {
254 expected("texture address mode");
255 return false;
256 }
257 } else if (stateName == "miplodbias") {
258 TIntermTyped* lodBias = nullptr;
259 if (! acceptLiteral(lodBias)) {
260 expected("lod bias");
261 return false;
262 }
263 } else if (stateName == "bordercolor") {
264 return false;
265 } else {
266 expected("texture state");
267 return false;
268 }
269
270 // SEMICOLON
271 if (! acceptTokenClass(EHTokSemicolon)) {
272 expected("semicolon");
273 return false;
274 }
275 } while (true);
276
277 if (! acceptTokenClass(EHTokRightBrace))
278 return false;
279
280 return true;
281}
282
283// sampler_declaration_dx9
284// : SAMPLER identifier EQUAL sampler_type sampler_state
285//
John Kesseniche4821e42016-07-16 10:19:43 -0600286bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600287{
288 if (! acceptTokenClass(EHTokSampler))
289 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700290
LoopDawg4886f692016-06-29 10:58:58 -0600291 // TODO: remove this when DX9 style declarations are implemented.
292 unimplemented("Direct3D 9 sampler declaration");
293
294 // read sampler name
295 HlslToken name;
296 if (! acceptIdentifier(name)) {
297 expected("sampler name");
298 return false;
299 }
300
301 if (! acceptTokenClass(EHTokAssign)) {
302 expected("=");
303 return false;
304 }
305
306 return false;
307}
308
John Kesseniche01a9bc2016-03-12 20:11:22 -0700309// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600310// : sampler_declaration_dx9 post_decls SEMICOLON
311// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600312// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600313// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600314// | typedef declaration
John Kessenich8f9fdc92017-03-30 16:22:26 -0600315// | NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
John Kessenich87142c72016-03-12 20:24:24 -0700316//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600317// declarator_list
318// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600319//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600320// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600321// : identifier array_specifier post_decls
322// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600323// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600324//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600325// Parsing has to go pretty far in to know whether it's a variable, prototype, or
326// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600327// as above. (The 'identifier' in the first item in init_declarator list is the
328// same as 'identifier' for function declarations.)
329//
John Kessenichca71d942017-03-07 20:44:09 -0700330// This can generate more than one subtree, one per initializer or a function body.
331// All initializer subtrees are put in their own aggregate node, making one top-level
332// node for all the initializers. Each function created is a top-level node to grow
333// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600334//
John Kessenichca71d942017-03-07 20:44:09 -0700335// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
336// each top-level node the declaration creates. Otherwise, if only one top-level
337// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700338//
John Kessenichca71d942017-03-07 20:44:09 -0700339bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700340{
John Kessenich8f9fdc92017-03-30 16:22:26 -0600341 // NAMESPACE IDENTIFIER LEFT_BRACE declaration_list RIGHT_BRACE
342 if (acceptTokenClass(EHTokNamespace)) {
343 HlslToken namespaceToken;
344 if (!acceptIdentifier(namespaceToken)) {
345 expected("namespace name");
346 return false;
347 }
348 parseContext.pushNamespace(*namespaceToken.string);
349 if (!acceptTokenClass(EHTokLeftBrace)) {
350 expected("{");
351 return false;
352 }
353 if (!acceptDeclarationList(nodeList)) {
354 expected("declaration list");
355 return false;
356 }
357 if (!acceptTokenClass(EHTokRightBrace)) {
358 expected("}");
359 return false;
360 }
361 parseContext.popNamespace();
362 return true;
363 }
364
John Kessenich54ee28f2017-03-11 14:13:00 -0700365 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600366
steve-lunarg1868b142016-10-20 13:07:10 -0600367 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700368 TFunctionDeclarator declarator;
369 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600370
John Kessenich5e69ec62016-07-05 00:02:40 -0600371 // typedef
372 bool typedefDecl = acceptTokenClass(EHTokTypedef);
373
John Kesseniche82061d2016-09-27 14:38:57 -0600374 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600375
376 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600377 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
378 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
379 // HLSL shaders, this will have to be a master level switch
380 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700381 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700382 // if (acceptSamplerDeclarationDX9(declaredType))
383 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600384
385 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700386 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700387 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600388
John Kessenich87142c72016-03-12 20:24:24 -0700389 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600390 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700391 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600392 while (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -0600393 const TString *fullName = idToken.string;
394 if (parseContext.symbolTable.atGlobalLevel())
395 parseContext.getFullNamespaceName(fullName);
John Kessenich78388722017-03-08 18:53:51 -0700396 if (peekTokenClass(EHTokLeftParen)) {
397 // looks like function parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600398
John Kessenich78388722017-03-08 18:53:51 -0700399 // Potentially rename shader entry point function. No-op most of the time.
John Kessenich8f9fdc92017-03-30 16:22:26 -0600400 parseContext.renameShaderFunction(fullName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600401
John Kessenich78388722017-03-08 18:53:51 -0700402 // function_parameters
John Kessenich8f9fdc92017-03-30 16:22:26 -0600403 declarator.function = new TFunction(fullName, declaredType);
John Kessenich088d52b2017-03-11 17:55:28 -0700404 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700405 expected("function parameter list");
406 return false;
407 }
408
John Kessenich630dd7d2016-06-12 23:52:12 -0600409 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700410 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600411
John Kessenichd5ed0b62016-07-04 17:32:45 -0600412 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700413 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600414 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700415 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600416 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600417 if (typedefDecl)
418 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700419 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600420 } else {
421 if (typedefDecl)
422 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700423 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600424 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600425 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600426 // A variable declaration. Fix the storage qualifier if it's a global.
427 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
428 declaredType.getQualifier().storage = EvqUniform;
429
John Kessenichecba76f2017-01-06 00:34:48 -0700430 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600431 // the number of types can expand when arrayness is different.
432 TType variableType;
433 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600434
John Kesseniche82061d2016-09-27 14:38:57 -0600435 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600436 TArraySizes* arraySizes = nullptr;
437 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600438
John Kesseniche82061d2016-09-27 14:38:57 -0600439 // Fix arrayness in the variableType
440 if (declaredType.isImplicitlySizedArray()) {
441 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
442 // of different sizes, for this case sharing the shallow copy of arrayness
443 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
444 variableType.newArraySizes(declaredType.getArraySizes());
445 }
446 if (arraySizes || variableType.isArray()) {
447 // In the most general case, arrayness is potentially coming both from the
448 // declared type and from the variable: "int[] a[];" or just one or the other.
449 // Merge it all to the variableType, so all arrayness is part of the variableType.
450 parseContext.arrayDimMerge(variableType, arraySizes);
451 }
452
LoopDawg4886f692016-06-29 10:58:58 -0600453 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600454 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600455 if (! acceptSamplerState())
456 return false;
457 }
458
John Kessenichd5ed0b62016-07-04 17:32:45 -0600459 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600460 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600461
462 // EQUAL assignment_expression
463 TIntermTyped* expressionNode = nullptr;
464 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600465 if (typedefDecl)
466 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600467 if (! acceptAssignmentExpression(expressionNode)) {
468 expected("initializer");
469 return false;
470 }
471 }
472
John Kessenich6dbc0a72016-09-27 19:13:05 -0600473 // TODO: things scoped within an annotation need their own name space;
474 // TODO: strings are not yet handled.
475 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
476 if (typedefDecl)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600477 parseContext.declareTypedef(idToken.loc, *fullName, variableType);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600478 else if (variableType.getBasicType() == EbtBlock)
John Kessenich8f9fdc92017-03-30 16:22:26 -0600479 parseContext.declareBlock(idToken.loc, variableType, fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600480 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700481 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600482 // this isn't really an individual variable, but a member of the $Global buffer
John Kessenich8f9fdc92017-03-30 16:22:26 -0600483 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *fullName);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600484 } else {
485 // Declare the variable and add any initializer code to the AST.
486 // The top-level node is always made into an aggregate, as that's
487 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700488 initializers = intermediate.growAggregate(initializers,
John Kessenich8f9fdc92017-03-30 16:22:26 -0600489 parseContext.declareVariable(idToken.loc, *fullName, variableType, expressionNode),
John Kessenichca71d942017-03-07 20:44:09 -0700490 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600491 }
492 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600493 }
John Kessenich5f934b02016-03-13 17:58:25 -0600494 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600495
496 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700497 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600498 continue;
499 }
500 };
501
John Kessenichca71d942017-03-07 20:44:09 -0700502 // The top-level initializer node is a sequence.
503 if (initializers != nullptr)
504 initializers->setOperator(EOpSequence);
505
506 // Add the initializers' aggregate to the nodeList we were handed.
507 if (nodeList)
508 nodeList = intermediate.growAggregate(nodeList, initializers);
509 else
510 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700511
John Kessenich078d7f22016-03-14 10:02:11 -0600512 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600513 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700514 // This may have been a false detection of what appeared to be a declaration, but
515 // was actually an assignment such as "float = 4", where "float" is an identifier.
516 // We put the token back to let further parsing happen for cases where that may
517 // happen. This errors on the side of caution, and mostly triggers the error.
518
519 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
520 recedeToken();
521 else
522 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600523 return false;
524 }
John Kessenichecba76f2017-01-06 00:34:48 -0700525
John Kesseniche01a9bc2016-03-12 20:11:22 -0700526 return true;
527}
528
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600529// control_declaration
530// : fully_specified_type identifier EQUAL expression
531//
532bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
533{
534 node = nullptr;
535
536 // fully_specified_type
537 TType type;
538 if (! acceptFullySpecifiedType(type))
539 return false;
540
John Kessenich057df292017-03-06 18:18:37 -0700541 // filter out type casts
542 if (peekTokenClass(EHTokLeftParen)) {
543 recedeToken();
544 return false;
545 }
546
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600547 // identifier
548 HlslToken idToken;
549 if (! acceptIdentifier(idToken)) {
550 expected("identifier");
551 return false;
552 }
553
554 // EQUAL
555 TIntermTyped* expressionNode = nullptr;
556 if (! acceptTokenClass(EHTokAssign)) {
557 expected("=");
558 return false;
559 }
560
561 // expression
562 if (! acceptExpression(expressionNode)) {
563 expected("initializer");
564 return false;
565 }
566
John Kesseniche82061d2016-09-27 14:38:57 -0600567 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600568
569 return true;
570}
571
John Kessenich87142c72016-03-12 20:24:24 -0700572// fully_specified_type
573// : type_specifier
574// | type_qualifier type_specifier
575//
576bool HlslGrammar::acceptFullySpecifiedType(TType& type)
577{
John Kessenich54ee28f2017-03-11 14:13:00 -0700578 TIntermNode* nodeList = nullptr;
579 return acceptFullySpecifiedType(type, nodeList);
580}
581bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
582{
John Kessenich87142c72016-03-12 20:24:24 -0700583 // type_qualifier
584 TQualifier qualifier;
585 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600586 if (! acceptQualifier(qualifier))
587 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600588 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700589
590 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700591 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700592 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700593 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700594 // qualifier. Back it out, if we did.
595 if (qualifier.sample)
596 recedeToken();
597
John Kessenich87142c72016-03-12 20:24:24 -0700598 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700599 }
John Kessenich3d157c52016-07-25 16:05:33 -0600600 if (type.getBasicType() == EbtBlock) {
601 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600602 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600603 // further, it can create an anonymous instance of the block
604 if (peekTokenClass(EHTokSemicolon))
605 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600606 } else {
607 // Some qualifiers are set when parsing the type. Merge those with
608 // whatever comes from acceptQualifier.
609 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700610
steve-lunargbb0183f2016-10-04 16:58:14 -0600611 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600612 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700613
steve-lunarg5da1f032017-02-12 17:50:28 -0700614 if (type.getQualifier().storage == EvqVaryingOut ||
615 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700616 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700617 qualifier.readonly = type.getQualifier().readonly;
618 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700619
620 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600621 }
John Kessenich87142c72016-03-12 20:24:24 -0700622
623 return true;
624}
625
John Kessenich630dd7d2016-06-12 23:52:12 -0600626// type_qualifier
627// : qualifier qualifier ...
628//
629// Zero or more of these, so this can't return false.
630//
John Kessenichb9e39122016-08-17 10:22:08 -0600631bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700632{
John Kessenich630dd7d2016-06-12 23:52:12 -0600633 do {
634 switch (peek()) {
635 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600636 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600637 break;
638 case EHTokExtern:
639 // TODO: no meaning in glslang?
640 break;
641 case EHTokShared:
642 // TODO: hint
643 break;
644 case EHTokGroupShared:
645 qualifier.storage = EvqShared;
646 break;
647 case EHTokUniform:
648 qualifier.storage = EvqUniform;
649 break;
650 case EHTokConst:
651 qualifier.storage = EvqConst;
652 break;
653 case EHTokVolatile:
654 qualifier.volatil = true;
655 break;
656 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600657 qualifier.smooth = true;
658 break;
659 case EHTokCentroid:
660 qualifier.centroid = true;
661 break;
662 case EHTokNointerpolation:
663 qualifier.flat = true;
664 break;
665 case EHTokNoperspective:
666 qualifier.nopersp = true;
667 break;
668 case EHTokSample:
669 qualifier.sample = true;
670 break;
671 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600672 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600673 break;
674 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600675 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600676 break;
677 case EHTokPrecise:
678 qualifier.noContraction = true;
679 break;
LoopDawg9249c702016-07-12 20:44:32 -0600680 case EHTokIn:
681 qualifier.storage = EvqIn;
682 break;
683 case EHTokOut:
684 qualifier.storage = EvqOut;
685 break;
686 case EHTokInOut:
687 qualifier.storage = EvqInOut;
688 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600689 case EHTokLayout:
690 if (! acceptLayoutQualifierList(qualifier))
691 return false;
692 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700693 case EHTokGloballyCoherent:
694 qualifier.coherent = true;
695 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600696 case EHTokInline:
697 // TODO: map this to SPIR-V function control
698 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700699
700 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
701 // for output variables.
702 case EHTokPoint:
703 qualifier.storage = EvqIn;
704 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
705 return false;
706 break;
707 case EHTokLine:
708 qualifier.storage = EvqIn;
709 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
710 return false;
711 break;
712 case EHTokTriangle:
713 qualifier.storage = EvqIn;
714 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
715 return false;
716 break;
717 case EHTokLineAdj:
718 qualifier.storage = EvqIn;
719 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
720 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700721 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700722 case EHTokTriangleAdj:
723 qualifier.storage = EvqIn;
724 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
725 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700726 break;
727
John Kessenich630dd7d2016-06-12 23:52:12 -0600728 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600729 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600730 }
731 advanceToken();
732 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700733}
734
John Kessenichb9e39122016-08-17 10:22:08 -0600735// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600736// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600737//
738// layout_qualifier
739// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600740// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600741//
742// Zero or more of these, so this can't return false.
743//
744bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
745{
746 if (! acceptTokenClass(EHTokLayout))
747 return false;
748
749 // LEFT_PAREN
750 if (! acceptTokenClass(EHTokLeftParen))
751 return false;
752
753 do {
754 // identifier
755 HlslToken idToken;
756 if (! acceptIdentifier(idToken))
757 break;
758
759 // EQUAL expression
760 if (acceptTokenClass(EHTokAssign)) {
761 TIntermTyped* expr;
762 if (! acceptConditionalExpression(expr)) {
763 expected("expression");
764 return false;
765 }
766 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
767 } else
768 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
769
770 // COMMA
771 if (! acceptTokenClass(EHTokComma))
772 break;
773 } while (true);
774
775 // RIGHT_PAREN
776 if (! acceptTokenClass(EHTokRightParen)) {
777 expected(")");
778 return false;
779 }
780
781 return true;
782}
783
LoopDawg6daaa4f2016-06-23 19:13:48 -0600784// template_type
785// : FLOAT
786// | DOUBLE
787// | INT
788// | DWORD
789// | UINT
790// | BOOL
791//
steve-lunargf49cdf42016-11-17 15:04:20 -0700792bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600793{
794 switch (peek()) {
795 case EHTokFloat:
796 basicType = EbtFloat;
797 break;
798 case EHTokDouble:
799 basicType = EbtDouble;
800 break;
801 case EHTokInt:
802 case EHTokDword:
803 basicType = EbtInt;
804 break;
805 case EHTokUint:
806 basicType = EbtUint;
807 break;
808 case EHTokBool:
809 basicType = EbtBool;
810 break;
811 default:
812 return false;
813 }
814
815 advanceToken();
816
817 return true;
818}
819
820// vector_template_type
821// : VECTOR
822// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
823//
824bool HlslGrammar::acceptVectorTemplateType(TType& type)
825{
826 if (! acceptTokenClass(EHTokVector))
827 return false;
828
829 if (! acceptTokenClass(EHTokLeftAngle)) {
830 // in HLSL, 'vector' alone means float4.
831 new(&type) TType(EbtFloat, EvqTemporary, 4);
832 return true;
833 }
834
835 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700836 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600837 expected("scalar type");
838 return false;
839 }
840
841 // COMMA
842 if (! acceptTokenClass(EHTokComma)) {
843 expected(",");
844 return false;
845 }
846
847 // integer
848 if (! peekTokenClass(EHTokIntConstant)) {
849 expected("literal integer");
850 return false;
851 }
852
853 TIntermTyped* vecSize;
854 if (! acceptLiteral(vecSize))
855 return false;
856
857 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
858
859 new(&type) TType(basicType, EvqTemporary, vecSizeI);
860
861 if (vecSizeI == 1)
862 type.makeVector();
863
864 if (!acceptTokenClass(EHTokRightAngle)) {
865 expected("right angle bracket");
866 return false;
867 }
868
869 return true;
870}
871
872// matrix_template_type
873// : MATRIX
874// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
875//
876bool HlslGrammar::acceptMatrixTemplateType(TType& type)
877{
878 if (! acceptTokenClass(EHTokMatrix))
879 return false;
880
881 if (! acceptTokenClass(EHTokLeftAngle)) {
882 // in HLSL, 'matrix' alone means float4x4.
883 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
884 return true;
885 }
886
887 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700888 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600889 expected("scalar type");
890 return false;
891 }
892
893 // COMMA
894 if (! acceptTokenClass(EHTokComma)) {
895 expected(",");
896 return false;
897 }
898
899 // integer rows
900 if (! peekTokenClass(EHTokIntConstant)) {
901 expected("literal integer");
902 return false;
903 }
904
905 TIntermTyped* rows;
906 if (! acceptLiteral(rows))
907 return false;
908
909 // COMMA
910 if (! acceptTokenClass(EHTokComma)) {
911 expected(",");
912 return false;
913 }
John Kessenichecba76f2017-01-06 00:34:48 -0700914
LoopDawg6daaa4f2016-06-23 19:13:48 -0600915 // integer cols
916 if (! peekTokenClass(EHTokIntConstant)) {
917 expected("literal integer");
918 return false;
919 }
920
921 TIntermTyped* cols;
922 if (! acceptLiteral(cols))
923 return false;
924
925 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600926 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
927 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600928
929 if (!acceptTokenClass(EHTokRightAngle)) {
930 expected("right angle bracket");
931 return false;
932 }
933
934 return true;
935}
936
steve-lunargf49cdf42016-11-17 15:04:20 -0700937// layout_geometry
938// : LINESTREAM
939// | POINTSTREAM
940// | TRIANGLESTREAM
941//
942bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
943{
944 // read geometry type
945 const EHlslTokenClass geometryType = peek();
946
947 switch (geometryType) {
948 case EHTokPointStream: geometry = ElgPoints; break;
949 case EHTokLineStream: geometry = ElgLineStrip; break;
950 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
951 default:
952 return false; // not a layout geometry
953 }
954
955 advanceToken(); // consume the layout keyword
956 return true;
957}
958
steve-lunarg858c9282017-01-07 08:54:10 -0700959// tessellation_decl_type
960// : INPUTPATCH
961// | OUTPUTPATCH
962//
963bool HlslGrammar::acceptTessellationDeclType()
964{
965 // read geometry type
966 const EHlslTokenClass tessType = peek();
967
968 switch (tessType) {
969 case EHTokInputPatch: break;
970 case EHTokOutputPatch: break;
971 default:
972 return false; // not a tessellation decl
973 }
974
975 advanceToken(); // consume the keyword
976 return true;
977}
978
979// tessellation_patch_template_type
980// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
981//
982bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
983{
984 if (! acceptTessellationDeclType())
985 return false;
986
987 if (! acceptTokenClass(EHTokLeftAngle))
988 return false;
989
990 if (! acceptType(type)) {
991 expected("tessellation patch type");
992 return false;
993 }
994
995 if (! acceptTokenClass(EHTokComma))
996 return false;
997
998 // integer size
999 if (! peekTokenClass(EHTokIntConstant)) {
1000 expected("literal integer");
1001 return false;
1002 }
1003
1004 TIntermTyped* size;
1005 if (! acceptLiteral(size))
1006 return false;
1007
1008 TArraySizes* arraySizes = new TArraySizes;
1009 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1010 type.newArraySizes(*arraySizes);
1011
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
1038 type.getQualifier().storage = EvqVaryingOut;
1039
1040 if (! acceptTokenClass(EHTokRightAngle)) {
1041 expected("right angle bracket");
1042 return false;
1043 }
1044
1045 return true;
1046}
John Kessenichecba76f2017-01-06 00:34:48 -07001047
John Kessenicha1e2d492016-09-20 13:22:58 -06001048// annotations
1049// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001050//
John Kessenicha1e2d492016-09-20 13:22:58 -06001051bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001052{
John Kessenicha1e2d492016-09-20 13:22:58 -06001053 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001054 return false;
1055
John Kessenicha1e2d492016-09-20 13:22:58 -06001056 // note that we are nesting a name space
1057 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001058
1059 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1060 do {
1061 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1062 while (acceptTokenClass(EHTokSemicolon))
1063 ;
1064
1065 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001066 break;
John Kessenich86f71382016-09-19 20:23:18 -06001067
1068 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001069 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001070 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001071 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001072 return false;
1073 }
1074 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001075
1076 parseContext.unnestAnnotations();
1077 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001078}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001079
LoopDawg4886f692016-06-29 10:58:58 -06001080// sampler_type
1081// : SAMPLER
1082// | SAMPLER1D
1083// | SAMPLER2D
1084// | SAMPLER3D
1085// | SAMPLERCUBE
1086// | SAMPLERSTATE
1087// | SAMPLERCOMPARISONSTATE
1088bool HlslGrammar::acceptSamplerType(TType& type)
1089{
1090 // read sampler type
1091 const EHlslTokenClass samplerType = peek();
1092
LoopDawga78b0292016-07-19 14:28:05 -06001093 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001094 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001095
LoopDawga78b0292016-07-19 14:28:05 -06001096 bool isShadow = false;
1097
LoopDawg4886f692016-06-29 10:58:58 -06001098 switch (samplerType) {
1099 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001100 case EHTokSampler1d: /*dim = Esd1D*/; break;
1101 case EHTokSampler2d: /*dim = Esd2D*/; break;
1102 case EHTokSampler3d: /*dim = Esd3D*/; break;
1103 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001104 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001105 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001106 default:
1107 return false; // not a sampler declaration
1108 }
1109
1110 advanceToken(); // consume the sampler type keyword
1111
1112 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001113
1114 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001115 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001116
1117 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1118
1119 return true;
1120}
1121
1122// texture_type
1123// | BUFFER
1124// | TEXTURE1D
1125// | TEXTURE1DARRAY
1126// | TEXTURE2D
1127// | TEXTURE2DARRAY
1128// | TEXTURE3D
1129// | TEXTURECUBE
1130// | TEXTURECUBEARRAY
1131// | TEXTURE2DMS
1132// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001133// | RWBUFFER
1134// | RWTEXTURE1D
1135// | RWTEXTURE1DARRAY
1136// | RWTEXTURE2D
1137// | RWTEXTURE2DARRAY
1138// | RWTEXTURE3D
1139
LoopDawg4886f692016-06-29 10:58:58 -06001140bool HlslGrammar::acceptTextureType(TType& type)
1141{
1142 const EHlslTokenClass textureType = peek();
1143
1144 TSamplerDim dim = EsdNone;
1145 bool array = false;
1146 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001147 bool image = false;
steve-lunargbf1537f2017-03-31 17:40:09 -06001148 bool combined = true;
LoopDawg4886f692016-06-29 10:58:58 -06001149
1150 switch (textureType) {
steve-lunargbf1537f2017-03-31 17:40:09 -06001151 case EHTokBuffer: dim = EsdBuffer; combined = false; break;
John Kessenichf36542f2017-03-31 14:39:30 -06001152 case EHTokTexture1d: dim = Esd1D; break;
1153 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1154 case EHTokTexture2d: dim = Esd2D; break;
1155 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1156 case EHTokTexture3d: dim = Esd3D; break;
1157 case EHTokTextureCube: dim = EsdCube; break;
1158 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1159 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1160 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1161 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1162 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1163 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1164 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1165 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1166 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001167 default:
1168 return false; // not a texture declaration
1169 }
1170
1171 advanceToken(); // consume the texture object keyword
1172
1173 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001174
LoopDawg4886f692016-06-29 10:58:58 -06001175 TIntermTyped* msCount = nullptr;
1176
steve-lunargbb0183f2016-10-04 16:58:14 -06001177 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001178 if (acceptTokenClass(EHTokLeftAngle)) {
1179 if (! acceptType(txType)) {
1180 expected("scalar or vector type");
1181 return false;
1182 }
1183
1184 const TBasicType basicRetType = txType.getBasicType() ;
1185
1186 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1187 unimplemented("basic type in texture");
1188 return false;
1189 }
1190
steve-lunargd53f7172016-07-27 15:46:48 -06001191 // Buffers can handle small mats if they fit in 4 components
1192 if (dim == EsdBuffer && txType.isMatrix()) {
1193 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1194 expected("components < 4 in matrix buffer type");
1195 return false;
1196 }
1197
1198 // TODO: except we don't handle it yet...
1199 unimplemented("matrix type in buffer");
1200 return false;
1201 }
1202
LoopDawg4886f692016-06-29 10:58:58 -06001203 if (!txType.isScalar() && !txType.isVector()) {
1204 expected("scalar or vector type");
1205 return false;
1206 }
1207
LoopDawg4886f692016-06-29 10:58:58 -06001208 if (ms && acceptTokenClass(EHTokComma)) {
1209 // read sample count for multisample types, if given
1210 if (! peekTokenClass(EHTokIntConstant)) {
1211 expected("multisample count");
1212 return false;
1213 }
1214
1215 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1216 return false;
1217 }
1218
1219 if (! acceptTokenClass(EHTokRightAngle)) {
1220 expected("right angle bracket");
1221 return false;
1222 }
1223 } else if (ms) {
1224 expected("texture type for multisample");
1225 return false;
John Kessenichf36542f2017-03-31 14:39:30 -06001226 } else if (image) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001227 expected("type for RWTexture/RWBuffer");
1228 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001229 }
1230
1231 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001232 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001233
1234 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001235 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001236
steve-lunarg4f2da272016-10-10 15:24:57 -06001237 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1238 if (image || dim == EsdBuffer)
1239 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001240
1241 // Non-image Buffers are combined
1242 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001243 sampler.set(txType.getBasicType(), dim, array);
1244 } else {
1245 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001246 if (image) {
1247 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1248 } else {
1249 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1250 }
steve-lunargd53f7172016-07-27 15:46:48 -06001251 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001252
1253 // Remember the declared vector size.
1254 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001255
steve-lunargbf1537f2017-03-31 17:40:09 -06001256 // Force uncombined, if necessary
1257 if (!combined)
1258 sampler.combined = false;
1259
LoopDawg4886f692016-06-29 10:58:58 -06001260 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001261 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001262
1263 return true;
1264}
1265
John Kessenich87142c72016-03-12 20:24:24 -07001266// If token is for a type, update 'type' with the type information,
1267// and return true and advance.
1268// Otherwise, return false, and don't advance
1269bool HlslGrammar::acceptType(TType& type)
1270{
John Kessenich54ee28f2017-03-11 14:13:00 -07001271 TIntermNode* nodeList = nullptr;
1272 return acceptType(type, nodeList);
1273}
1274bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1275{
steve-lunarg3226b082016-10-26 19:18:55 -06001276 // Basic types for min* types, broken out here in case of future
1277 // changes, e.g, to use native halfs.
1278 static const TBasicType min16float_bt = EbtFloat;
1279 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001280 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001281 static const TBasicType min16int_bt = EbtInt;
1282 static const TBasicType min12int_bt = EbtInt;
1283 static const TBasicType min16uint_bt = EbtUint;
1284
John Kessenich9c86c6a2016-05-03 22:49:24 -06001285 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001286 case EHTokVector:
1287 return acceptVectorTemplateType(type);
1288 break;
1289
1290 case EHTokMatrix:
1291 return acceptMatrixTemplateType(type);
1292 break;
1293
steve-lunargf49cdf42016-11-17 15:04:20 -07001294 case EHTokPointStream: // fall through
1295 case EHTokLineStream: // ...
1296 case EHTokTriangleStream: // ...
1297 {
1298 TLayoutGeometry geometry;
1299 if (! acceptStreamOutTemplateType(type, geometry))
1300 return false;
1301
1302 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1303 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001304
steve-lunargf49cdf42016-11-17 15:04:20 -07001305 return true;
1306 }
1307
steve-lunarg858c9282017-01-07 08:54:10 -07001308 case EHTokInputPatch: // fall through
1309 case EHTokOutputPatch: // ...
1310 {
1311 if (! acceptTessellationPatchTemplateType(type))
1312 return false;
1313
1314 return true;
1315 }
1316
LoopDawg4886f692016-06-29 10:58:58 -06001317 case EHTokSampler: // fall through
1318 case EHTokSampler1d: // ...
1319 case EHTokSampler2d: // ...
1320 case EHTokSampler3d: // ...
1321 case EHTokSamplerCube: // ...
1322 case EHTokSamplerState: // ...
1323 case EHTokSamplerComparisonState: // ...
1324 return acceptSamplerType(type);
1325 break;
1326
1327 case EHTokBuffer: // fall through
1328 case EHTokTexture1d: // ...
1329 case EHTokTexture1darray: // ...
1330 case EHTokTexture2d: // ...
1331 case EHTokTexture2darray: // ...
1332 case EHTokTexture3d: // ...
1333 case EHTokTextureCube: // ...
1334 case EHTokTextureCubearray: // ...
1335 case EHTokTexture2DMS: // ...
1336 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001337 case EHTokRWTexture1d: // ...
1338 case EHTokRWTexture1darray: // ...
1339 case EHTokRWTexture2d: // ...
1340 case EHTokRWTexture2darray: // ...
1341 case EHTokRWTexture3d: // ...
1342 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001343 return acceptTextureType(type);
1344 break;
1345
steve-lunarg5da1f032017-02-12 17:50:28 -07001346 case EHTokAppendStructuredBuffer:
1347 case EHTokByteAddressBuffer:
1348 case EHTokConsumeStructuredBuffer:
1349 case EHTokRWByteAddressBuffer:
1350 case EHTokRWStructuredBuffer:
1351 case EHTokStructuredBuffer:
1352 return acceptStructBufferType(type);
1353 break;
1354
John Kessenich27ffb292017-03-03 17:01:01 -07001355 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001356 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001357 case EHTokCBuffer:
1358 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001359 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001360
1361 case EHTokIdentifier:
1362 // An identifier could be for a user-defined type.
1363 // Note we cache the symbol table lookup, to save for a later rule
1364 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001365 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001366 advanceToken();
1367 return true;
1368 } else
1369 return false;
1370
John Kessenich71351de2016-06-08 12:50:56 -06001371 case EHTokVoid:
1372 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001373 break;
John Kessenich71351de2016-06-08 12:50:56 -06001374
John Kessenicha1e2d492016-09-20 13:22:58 -06001375 case EHTokString:
1376 new(&type) TType(EbtString);
1377 break;
1378
John Kessenich87142c72016-03-12 20:24:24 -07001379 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001380 new(&type) TType(EbtFloat);
1381 break;
John Kessenich87142c72016-03-12 20:24:24 -07001382 case EHTokFloat1:
1383 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001384 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001385 break;
John Kessenich87142c72016-03-12 20:24:24 -07001386 case EHTokFloat2:
1387 new(&type) TType(EbtFloat, EvqTemporary, 2);
1388 break;
1389 case EHTokFloat3:
1390 new(&type) TType(EbtFloat, EvqTemporary, 3);
1391 break;
1392 case EHTokFloat4:
1393 new(&type) TType(EbtFloat, EvqTemporary, 4);
1394 break;
1395
John Kessenich71351de2016-06-08 12:50:56 -06001396 case EHTokDouble:
1397 new(&type) TType(EbtDouble);
1398 break;
1399 case EHTokDouble1:
1400 new(&type) TType(EbtDouble);
1401 type.makeVector();
1402 break;
1403 case EHTokDouble2:
1404 new(&type) TType(EbtDouble, EvqTemporary, 2);
1405 break;
1406 case EHTokDouble3:
1407 new(&type) TType(EbtDouble, EvqTemporary, 3);
1408 break;
1409 case EHTokDouble4:
1410 new(&type) TType(EbtDouble, EvqTemporary, 4);
1411 break;
1412
1413 case EHTokInt:
1414 case EHTokDword:
1415 new(&type) TType(EbtInt);
1416 break;
1417 case EHTokInt1:
1418 new(&type) TType(EbtInt);
1419 type.makeVector();
1420 break;
John Kessenich87142c72016-03-12 20:24:24 -07001421 case EHTokInt2:
1422 new(&type) TType(EbtInt, EvqTemporary, 2);
1423 break;
1424 case EHTokInt3:
1425 new(&type) TType(EbtInt, EvqTemporary, 3);
1426 break;
1427 case EHTokInt4:
1428 new(&type) TType(EbtInt, EvqTemporary, 4);
1429 break;
1430
John Kessenich71351de2016-06-08 12:50:56 -06001431 case EHTokUint:
1432 new(&type) TType(EbtUint);
1433 break;
1434 case EHTokUint1:
1435 new(&type) TType(EbtUint);
1436 type.makeVector();
1437 break;
1438 case EHTokUint2:
1439 new(&type) TType(EbtUint, EvqTemporary, 2);
1440 break;
1441 case EHTokUint3:
1442 new(&type) TType(EbtUint, EvqTemporary, 3);
1443 break;
1444 case EHTokUint4:
1445 new(&type) TType(EbtUint, EvqTemporary, 4);
1446 break;
1447
1448 case EHTokBool:
1449 new(&type) TType(EbtBool);
1450 break;
1451 case EHTokBool1:
1452 new(&type) TType(EbtBool);
1453 type.makeVector();
1454 break;
John Kessenich87142c72016-03-12 20:24:24 -07001455 case EHTokBool2:
1456 new(&type) TType(EbtBool, EvqTemporary, 2);
1457 break;
1458 case EHTokBool3:
1459 new(&type) TType(EbtBool, EvqTemporary, 3);
1460 break;
1461 case EHTokBool4:
1462 new(&type) TType(EbtBool, EvqTemporary, 4);
1463 break;
1464
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001465 case EHTokHalf:
1466 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1467 break;
1468 case EHTokHalf1:
1469 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1470 type.makeVector();
1471 break;
1472 case EHTokHalf2:
1473 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1474 break;
1475 case EHTokHalf3:
1476 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1477 break;
1478 case EHTokHalf4:
1479 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1480 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001481
steve-lunarg3226b082016-10-26 19:18:55 -06001482 case EHTokMin16float:
1483 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1484 break;
1485 case EHTokMin16float1:
1486 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1487 type.makeVector();
1488 break;
1489 case EHTokMin16float2:
1490 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1491 break;
1492 case EHTokMin16float3:
1493 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1494 break;
1495 case EHTokMin16float4:
1496 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1497 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001498
steve-lunarg3226b082016-10-26 19:18:55 -06001499 case EHTokMin10float:
1500 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1501 break;
1502 case EHTokMin10float1:
1503 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1504 type.makeVector();
1505 break;
1506 case EHTokMin10float2:
1507 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1508 break;
1509 case EHTokMin10float3:
1510 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1511 break;
1512 case EHTokMin10float4:
1513 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1514 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001515
steve-lunarg3226b082016-10-26 19:18:55 -06001516 case EHTokMin16int:
1517 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1518 break;
1519 case EHTokMin16int1:
1520 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1521 type.makeVector();
1522 break;
1523 case EHTokMin16int2:
1524 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1525 break;
1526 case EHTokMin16int3:
1527 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1528 break;
1529 case EHTokMin16int4:
1530 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1531 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001532
steve-lunarg3226b082016-10-26 19:18:55 -06001533 case EHTokMin12int:
1534 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1535 break;
1536 case EHTokMin12int1:
1537 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1538 type.makeVector();
1539 break;
1540 case EHTokMin12int2:
1541 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1542 break;
1543 case EHTokMin12int3:
1544 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1545 break;
1546 case EHTokMin12int4:
1547 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1548 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001549
steve-lunarg3226b082016-10-26 19:18:55 -06001550 case EHTokMin16uint:
1551 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1552 break;
1553 case EHTokMin16uint1:
1554 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1555 type.makeVector();
1556 break;
1557 case EHTokMin16uint2:
1558 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1559 break;
1560 case EHTokMin16uint3:
1561 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1562 break;
1563 case EHTokMin16uint4:
1564 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1565 break;
1566
John Kessenich0133c122016-05-20 12:17:26 -06001567 case EHTokInt1x1:
1568 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1569 break;
1570 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001571 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001572 break;
1573 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001574 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001575 break;
1576 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001577 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001578 break;
1579 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001580 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001581 break;
1582 case EHTokInt2x2:
1583 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1584 break;
1585 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001586 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001587 break;
1588 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001589 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001590 break;
1591 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001592 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001593 break;
1594 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001595 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001596 break;
1597 case EHTokInt3x3:
1598 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1599 break;
1600 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001601 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001602 break;
1603 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001604 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001605 break;
1606 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001607 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001608 break;
1609 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001610 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001611 break;
1612 case EHTokInt4x4:
1613 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1614 break;
1615
John Kessenich71351de2016-06-08 12:50:56 -06001616 case EHTokUint1x1:
1617 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1618 break;
1619 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001621 break;
1622 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001623 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001624 break;
1625 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001626 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001627 break;
1628 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001629 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001630 break;
1631 case EHTokUint2x2:
1632 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1633 break;
1634 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001635 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001636 break;
1637 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001638 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001639 break;
1640 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001641 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001642 break;
1643 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001644 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001645 break;
1646 case EHTokUint3x3:
1647 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1648 break;
1649 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001650 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001651 break;
1652 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001653 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001654 break;
1655 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001656 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001657 break;
1658 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001659 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001660 break;
1661 case EHTokUint4x4:
1662 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1663 break;
1664
1665 case EHTokBool1x1:
1666 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1667 break;
1668 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001669 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001670 break;
1671 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001672 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001673 break;
1674 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001675 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001676 break;
1677 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001678 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001679 break;
1680 case EHTokBool2x2:
1681 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1682 break;
1683 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001684 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001685 break;
1686 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001687 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001688 break;
1689 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001690 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001691 break;
1692 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001693 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001694 break;
1695 case EHTokBool3x3:
1696 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1697 break;
1698 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001699 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001700 break;
1701 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001702 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001703 break;
1704 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001705 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001706 break;
1707 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001708 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001709 break;
1710 case EHTokBool4x4:
1711 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1712 break;
1713
John Kessenich0133c122016-05-20 12:17:26 -06001714 case EHTokFloat1x1:
1715 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1716 break;
1717 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001718 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001719 break;
1720 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001721 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001722 break;
1723 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001724 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001725 break;
1726 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001727 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001728 break;
John Kessenich87142c72016-03-12 20:24:24 -07001729 case EHTokFloat2x2:
1730 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1731 break;
1732 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001733 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001734 break;
1735 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001736 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001737 break;
John Kessenich0133c122016-05-20 12:17:26 -06001738 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001739 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001740 break;
John Kessenich87142c72016-03-12 20:24:24 -07001741 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001742 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001743 break;
1744 case EHTokFloat3x3:
1745 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1746 break;
1747 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001748 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001749 break;
John Kessenich0133c122016-05-20 12:17:26 -06001750 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001751 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001752 break;
John Kessenich87142c72016-03-12 20:24:24 -07001753 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001754 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001755 break;
1756 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001757 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001758 break;
1759 case EHTokFloat4x4:
1760 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1761 break;
1762
John Kessenich0133c122016-05-20 12:17:26 -06001763 case EHTokDouble1x1:
1764 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1765 break;
1766 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001767 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001768 break;
1769 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001770 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001771 break;
1772 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001773 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001774 break;
1775 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001776 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001777 break;
1778 case EHTokDouble2x2:
1779 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1780 break;
1781 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001782 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001783 break;
1784 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001785 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001786 break;
1787 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001788 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001789 break;
1790 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001791 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001792 break;
1793 case EHTokDouble3x3:
1794 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1795 break;
1796 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001797 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001798 break;
1799 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001800 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001801 break;
1802 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001803 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001804 break;
1805 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001806 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001807 break;
1808 case EHTokDouble4x4:
1809 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1810 break;
1811
John Kessenich87142c72016-03-12 20:24:24 -07001812 default:
1813 return false;
1814 }
1815
1816 advanceToken();
1817
1818 return true;
1819}
1820
John Kesseniche6e74942016-06-11 16:43:14 -06001821// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001822// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1823// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001824// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001825//
1826// struct_type
1827// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001828// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001829// | CBUFFER
1830// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001831//
John Kessenich54ee28f2017-03-11 14:13:00 -07001832bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001833{
John Kessenichb804de62016-09-05 12:19:18 -06001834 // This storage qualifier will tell us whether it's an AST
1835 // block type or just a generic structure type.
1836 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001837
1838 // CBUFFER
1839 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001840 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001841 // TBUFFER
1842 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001843 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001844 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001845 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001846 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001847 return false;
1848
1849 // IDENTIFIER
1850 TString structName = "";
1851 if (peekTokenClass(EHTokIdentifier)) {
1852 structName = *token.string;
1853 advanceToken();
1854 }
1855
John Kessenich3d157c52016-07-25 16:05:33 -06001856 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001857 TQualifier postDeclQualifier;
1858 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001859 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001860
John Kessenichf3d88bd2017-03-19 12:24:29 -06001861 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001862 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001863 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001864 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1865 // struct_type IDENTIFIER
1866 return true;
1867 } else {
1868 expected("{");
1869 return false;
1870 }
John Kesseniche6e74942016-06-11 16:43:14 -06001871 }
1872
John Kessenichf3d88bd2017-03-19 12:24:29 -06001873
John Kesseniche6e74942016-06-11 16:43:14 -06001874 // struct_declaration_list
1875 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001876 // Save each member function so they can be processed after we have a fully formed 'this'.
1877 TVector<TFunctionDeclarator> functionDeclarators;
1878
1879 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001880 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001881 parseContext.popNamespace();
1882
1883 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001884 expected("struct member declarations");
1885 return false;
1886 }
1887
1888 // RIGHT_BRACE
1889 if (! acceptTokenClass(EHTokRightBrace)) {
1890 expected("}");
1891 return false;
1892 }
1893
1894 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001895 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001896 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001897 else {
John Kessenich7735b942016-09-05 12:40:06 -06001898 postDeclQualifier.storage = storageQualifier;
1899 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001900 }
John Kesseniche6e74942016-06-11 16:43:14 -06001901
John Kessenich727b3742017-02-03 17:57:55 -07001902 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001903
John Kessenich4960baa2017-03-19 18:09:59 -06001904 // For member functions: now that we know the type of 'this', go back and
1905 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1906 // - parse the functions, their tokens were saved for deferred parsing (now)
1907 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1908 // update signature
1909 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001910 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001911 }
1912
John Kessenichf3d88bd2017-03-19 12:24:29 -06001913 // All member functions get parsed inside the class/struct namespace and with the
1914 // class/struct members in a symbol-table level.
1915 parseContext.pushNamespace(structName);
John Kessenich37789792017-03-21 23:56:40 -06001916 parseContext.pushThisScope(type);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001917 bool deferredSuccess = true;
1918 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1919 // parse body
1920 pushTokenStream(functionDeclarators[b].body);
1921 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1922 deferredSuccess = false;
1923 popTokenStream();
1924 }
John Kessenich37789792017-03-21 23:56:40 -06001925 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001926 parseContext.popNamespace();
1927
1928 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001929}
1930
steve-lunarg5da1f032017-02-12 17:50:28 -07001931// struct_buffer
1932// : APPENDSTRUCTUREDBUFFER
1933// | BYTEADDRESSBUFFER
1934// | CONSUMESTRUCTUREDBUFFER
1935// | RWBYTEADDRESSBUFFER
1936// | RWSTRUCTUREDBUFFER
1937// | STRUCTUREDBUFFER
1938bool HlslGrammar::acceptStructBufferType(TType& type)
1939{
1940 const EHlslTokenClass structBuffType = peek();
1941
1942 // TODO: globallycoherent
1943 bool hasTemplateType = true;
1944 bool readonly = false;
1945
1946 TStorageQualifier storage = EvqBuffer;
1947
1948 switch (structBuffType) {
1949 case EHTokAppendStructuredBuffer:
1950 unimplemented("AppendStructuredBuffer");
1951 return false;
1952 case EHTokByteAddressBuffer:
1953 hasTemplateType = false;
1954 readonly = true;
1955 break;
1956 case EHTokConsumeStructuredBuffer:
1957 unimplemented("ConsumeStructuredBuffer");
1958 return false;
1959 case EHTokRWByteAddressBuffer:
1960 hasTemplateType = false;
1961 break;
1962 case EHTokRWStructuredBuffer:
1963 break;
1964 case EHTokStructuredBuffer:
1965 readonly = true;
1966 break;
1967 default:
1968 return false; // not a structure buffer type
1969 }
1970
1971 advanceToken(); // consume the structure keyword
1972
1973 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1974 TType* templateType = new TType;
1975
1976 if (hasTemplateType) {
1977 if (! acceptTokenClass(EHTokLeftAngle)) {
1978 expected("left angle bracket");
1979 return false;
1980 }
1981
1982 if (! acceptType(*templateType)) {
1983 expected("type");
1984 return false;
1985 }
1986 if (! acceptTokenClass(EHTokRightAngle)) {
1987 expected("right angle bracket");
1988 return false;
1989 }
1990 } else {
1991 // byte address buffers have no explicit type.
1992 TType uintType(EbtUint, storage);
1993 templateType->shallowCopy(uintType);
1994 }
1995
1996 // Create an unsized array out of that type.
1997 // TODO: does this work if it's already an array type?
1998 TArraySizes unsizedArray;
1999 unsizedArray.addInnerSize(UnsizedArraySize);
2000 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002001 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002002
2003 // field name is canonical for all structbuffers
2004 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002005
2006 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07002007
steve-lunarg5da1f032017-02-12 17:50:28 -07002008 TTypeList* blockStruct = new TTypeList;
2009 TTypeLoc member = { templateType, token.loc };
2010 blockStruct->push_back(member);
2011
steve-lunargdd8287a2017-02-23 18:04:12 -07002012 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002013 TType blockType(blockStruct, "", templateType->getQualifier());
2014
steve-lunargdd8287a2017-02-23 18:04:12 -07002015 blockType.getQualifier().storage = storage;
2016 blockType.getQualifier().readonly = readonly;
2017
2018 // We may have created an equivalent type before, in which case we should use its
2019 // deep structure.
2020 parseContext.shareStructBufferType(blockType);
2021
steve-lunarg5da1f032017-02-12 17:50:28 -07002022 type.shallowCopy(blockType);
2023
2024 return true;
2025}
2026
John Kesseniche6e74942016-06-11 16:43:14 -06002027// struct_declaration_list
2028// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2029//
2030// struct_declaration
2031// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002032// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002033//
2034// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002035// : IDENTIFIER post_decls
2036// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002037// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002038//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002039bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002040 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002041{
2042 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002043 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002044
2045 do {
2046 // success on seeing the RIGHT_BRACE coming up
2047 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002048 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002049
2050 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002051
2052 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002053
2054 // fully_specified_type
2055 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002056 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002057 expected("member type");
2058 return false;
2059 }
2060
2061 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002062 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002063 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002064 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002065 expected("member name");
2066 return false;
2067 }
2068
John Kessenich54ee28f2017-03-11 14:13:00 -07002069 if (peekTokenClass(EHTokLeftParen)) {
2070 // function_parameters
2071 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002072 declarators.resize(declarators.size() + 1);
2073 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002074 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2075 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002076 if (functionDefinitionAccepted)
2077 break;
2078 }
2079 expected("member-function definition");
2080 return false;
2081 } else {
2082 // add it to the list of members
2083 TTypeLoc member = { new TType(EbtVoid), token.loc };
2084 member.type->shallowCopy(memberType);
2085 member.type->setFieldName(*idToken.string);
2086 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002087
John Kessenich54ee28f2017-03-11 14:13:00 -07002088 // array_specifier
2089 TArraySizes* arraySizes = nullptr;
2090 acceptArraySpecifier(arraySizes);
2091 if (arraySizes)
2092 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002093
John Kessenich54ee28f2017-03-11 14:13:00 -07002094 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002095
John Kessenich54ee28f2017-03-11 14:13:00 -07002096 // EQUAL assignment_expression
2097 if (acceptTokenClass(EHTokAssign)) {
2098 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2099 TIntermTyped* expressionNode = nullptr;
2100 if (! acceptAssignmentExpression(expressionNode)) {
2101 expected("initializer");
2102 return false;
2103 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002104 }
2105 }
John Kesseniche6e74942016-06-11 16:43:14 -06002106 // success on seeing the SEMICOLON coming up
2107 if (peekTokenClass(EHTokSemicolon))
2108 break;
2109
2110 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002111 if (acceptTokenClass(EHTokComma))
2112 declarator_list = true;
2113 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002114 expected(",");
2115 return false;
2116 }
2117
2118 } while (true);
2119
2120 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002121 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002122 expected(";");
2123 return false;
2124 }
2125
2126 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002127
John Kessenichb16f7e62017-03-11 19:32:47 -07002128 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002129}
2130
John Kessenich54ee28f2017-03-11 14:13:00 -07002131// member_function_definition
2132// | function_parameters post_decls compound_statement
2133//
2134// Expects type to have EvqGlobal for a static member and
2135// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002136bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2137 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002138{
John Kessenich54ee28f2017-03-11 14:13:00 -07002139 bool accepted = false;
2140
John Kessenich4dc835c2017-03-28 23:43:10 -06002141 const TString* functionName = &memberName;
2142 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002143 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002144 if (type.getQualifier().storage == EvqTemporary)
2145 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002146 else
2147 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002148
2149 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002150 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002151 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002152 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002153
2154 // compound_statement (function body definition)
2155 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002156 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002157 declarator.body = new TVector<HlslToken>;
2158 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002159 }
2160 } else
2161 expected("function parameter list");
2162
John Kessenich54ee28f2017-03-11 14:13:00 -07002163 return accepted;
2164}
2165
John Kessenich5f934b02016-03-13 17:58:25 -06002166// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002167// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002168// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002169//
2170bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2171{
John Kessenich078d7f22016-03-14 10:02:11 -06002172 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002173 if (! acceptTokenClass(EHTokLeftParen))
2174 return false;
2175
John Kessenich71351de2016-06-08 12:50:56 -06002176 // VOID RIGHT_PAREN
2177 if (! acceptTokenClass(EHTokVoid)) {
2178 do {
2179 // parameter_declaration
2180 if (! acceptParameterDeclaration(function))
2181 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002182
John Kessenich71351de2016-06-08 12:50:56 -06002183 // COMMA
2184 if (! acceptTokenClass(EHTokComma))
2185 break;
2186 } while (true);
2187 }
John Kessenich5f934b02016-03-13 17:58:25 -06002188
John Kessenich078d7f22016-03-14 10:02:11 -06002189 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002190 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002191 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002192 return false;
2193 }
2194
2195 return true;
2196}
2197
steve-lunarg26d31452016-12-23 18:56:57 -07002198// default_parameter_declaration
2199// : EQUAL conditional_expression
2200// : EQUAL initializer
2201bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2202{
2203 node = nullptr;
2204
2205 // Valid not to have a default_parameter_declaration
2206 if (!acceptTokenClass(EHTokAssign))
2207 return true;
2208
2209 if (!acceptConditionalExpression(node)) {
2210 if (!acceptInitializer(node))
2211 return false;
2212
2213 // For initializer lists, we have to const-fold into a constructor for the type, so build
2214 // that.
2215 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2216 if (constructor == nullptr) // cannot construct
2217 return false;
2218
2219 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002220 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002221 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002222
steve-lunarg26d31452016-12-23 18:56:57 -07002223 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2224 }
2225
2226 // If this is simply a constant, we can use it directly.
2227 if (node->getAsConstantUnion())
2228 return true;
2229
2230 // Otherwise, it has to be const-foldable.
2231 TIntermTyped* origNode = node;
2232
2233 node = intermediate.fold(node->getAsAggregate());
2234
2235 if (node != nullptr && origNode != node)
2236 return true;
2237
2238 parseContext.error(token.loc, "invalid default parameter value", "", "");
2239
2240 return false;
2241}
2242
John Kessenich5f934b02016-03-13 17:58:25 -06002243// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002244// : fully_specified_type post_decls [ = default_parameter_declaration ]
2245// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002246//
2247bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2248{
2249 // fully_specified_type
2250 TType* type = new TType;
2251 if (! acceptFullySpecifiedType(*type))
2252 return false;
2253
2254 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002255 HlslToken idToken;
2256 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002257
John Kessenich19b92ff2016-06-19 11:50:34 -06002258 // array_specifier
2259 TArraySizes* arraySizes = nullptr;
2260 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002261 if (arraySizes) {
2262 if (arraySizes->isImplicit()) {
2263 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2264 return false;
2265 }
2266
John Kessenich19b92ff2016-06-19 11:50:34 -06002267 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002268 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002269
2270 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002271 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002272
steve-lunarg26d31452016-12-23 18:56:57 -07002273 TIntermTyped* defaultValue;
2274 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2275 return false;
2276
John Kessenich5aa59e22016-06-17 15:50:47 -06002277 parseContext.paramFix(*type);
2278
steve-lunarg26d31452016-12-23 18:56:57 -07002279 // If any prior parameters have default values, all the parameters after that must as well.
2280 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2281 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2282 return false;
2283 }
2284
2285 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002286 function.addParameter(param);
2287
2288 return true;
2289}
2290
2291// Do the work to create the function definition in addition to
2292// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002293//
2294// If 'deferredTokens' are passed in, just get the token stream,
2295// don't process.
2296//
2297bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2298 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002299{
John Kessenich088d52b2017-03-11 17:55:28 -07002300 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002301
John Kessenichb16f7e62017-03-11 19:32:47 -07002302 if (deferredTokens)
2303 return captureBlockTokens(*deferredTokens);
2304 else
John Kessenich4960baa2017-03-19 18:09:59 -06002305 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002306}
2307
2308bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2309{
2310 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002311 TIntermNode* entryPointNode = nullptr;
2312
John Kessenich077e0522016-06-09 02:02:17 -06002313 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002314 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2315 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002316
2317 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002318 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002319 if (! acceptCompoundStatement(functionBody))
2320 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002321
John Kessenich54ee28f2017-03-11 14:13:00 -07002322 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002323 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002324
2325 // Hook up the 1 or 2 function definitions.
2326 nodeList = intermediate.growAggregate(nodeList, functionNode);
2327 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002328
2329 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002330}
2331
John Kessenich0d2b6de2016-06-05 11:23:11 -06002332// Accept an expression with parenthesis around it, where
2333// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002334// syntactically required ones like in "if ( expression )".
2335//
2336// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002337//
2338// Note this one is not set up to be speculative; as it gives
2339// errors if not found.
2340//
2341bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2342{
2343 // LEFT_PAREN
2344 if (! acceptTokenClass(EHTokLeftParen))
2345 expected("(");
2346
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002347 bool decl = false;
2348 TIntermNode* declNode = nullptr;
2349 decl = acceptControlDeclaration(declNode);
2350 if (decl) {
2351 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2352 expected("initialized declaration");
2353 return false;
2354 } else
2355 expression = declNode->getAsTyped();
2356 } else {
2357 // no declaration
2358 if (! acceptExpression(expression)) {
2359 expected("expression");
2360 return false;
2361 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002362 }
2363
2364 // RIGHT_PAREN
2365 if (! acceptTokenClass(EHTokRightParen))
2366 expected(")");
2367
2368 return true;
2369}
2370
John Kessenich34fb0362016-05-03 23:17:20 -06002371// The top-level full expression recognizer.
2372//
John Kessenich87142c72016-03-12 20:24:24 -07002373// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002374// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002375//
2376bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2377{
LoopDawgef764a22016-06-03 09:17:51 -06002378 node = nullptr;
2379
John Kessenich34fb0362016-05-03 23:17:20 -06002380 // assignment_expression
2381 if (! acceptAssignmentExpression(node))
2382 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002383
John Kessenich34fb0362016-05-03 23:17:20 -06002384 if (! peekTokenClass(EHTokComma))
2385 return true;
2386
2387 do {
2388 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002389 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002390 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002391
John Kessenich34fb0362016-05-03 23:17:20 -06002392 // ... assignment_expression
2393 TIntermTyped* rightNode = nullptr;
2394 if (! acceptAssignmentExpression(rightNode)) {
2395 expected("assignment expression");
2396 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002397 }
2398
John Kessenich34fb0362016-05-03 23:17:20 -06002399 node = intermediate.addComma(node, rightNode, loc);
2400
2401 if (! peekTokenClass(EHTokComma))
2402 return true;
2403 } while (true);
2404}
2405
John Kessenich07354242016-07-01 19:58:06 -06002406// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002407// : LEFT_BRACE RIGHT_BRACE
2408// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002409//
2410// initializer_list
2411// : assignment_expression COMMA assignment_expression COMMA ...
2412//
2413bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2414{
2415 // LEFT_BRACE
2416 if (! acceptTokenClass(EHTokLeftBrace))
2417 return false;
2418
John Kessenich98ad4852016-11-27 17:39:07 -07002419 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002420 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002421 if (acceptTokenClass(EHTokRightBrace)) {
2422 // a zero-length initializer list
2423 node = intermediate.makeAggregate(loc);
2424 return true;
2425 }
2426
2427 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002428 node = nullptr;
2429 do {
2430 // assignment_expression
2431 TIntermTyped* expr;
2432 if (! acceptAssignmentExpression(expr)) {
2433 expected("assignment expression in initializer list");
2434 return false;
2435 }
2436 node = intermediate.growAggregate(node, expr, loc);
2437
2438 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002439 if (acceptTokenClass(EHTokComma)) {
2440 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2441 return true;
John Kessenich07354242016-07-01 19:58:06 -06002442 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002443 }
John Kessenich07354242016-07-01 19:58:06 -06002444
2445 // RIGHT_BRACE
2446 if (acceptTokenClass(EHTokRightBrace))
2447 return true;
2448
2449 expected(", or }");
2450 return false;
2451 } while (true);
2452}
2453
John Kessenich34fb0362016-05-03 23:17:20 -06002454// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002455// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002456//
2457// a op (b op (c op d))
2458//
2459// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002460// : initializer
2461// | conditional_expression
2462// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002463//
2464bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2465{
John Kessenich07354242016-07-01 19:58:06 -06002466 // initializer
2467 if (peekTokenClass(EHTokLeftBrace)) {
2468 if (acceptInitializer(node))
2469 return true;
2470
2471 expected("initializer");
2472 return false;
2473 }
2474
John Kessenich00957f82016-07-27 10:39:57 -06002475 // conditional_expression
2476 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002477 return false;
2478
John Kessenich07354242016-07-01 19:58:06 -06002479 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002480 TOperator assignOp = HlslOpMap::assignment(peek());
2481 if (assignOp == EOpNull)
2482 return true;
2483
John Kessenich00957f82016-07-27 10:39:57 -06002484 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002485 TSourceLoc loc = token.loc;
2486 advanceToken();
2487
John Kessenich00957f82016-07-27 10:39:57 -06002488 // conditional_expression assign_op conditional_expression ...
2489 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002490 // gets the right-to-left associativity.
2491 TIntermTyped* rightNode = nullptr;
2492 if (! acceptAssignmentExpression(rightNode)) {
2493 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002494 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002495 }
2496
John Kessenichd21baed2016-09-16 03:05:12 -06002497 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002498 node = parseContext.handleLvalue(loc, "assign", node);
2499
John Kessenichfea226b2016-07-28 17:53:56 -06002500 if (node == nullptr) {
2501 parseContext.error(loc, "could not create assignment", "", "");
2502 return false;
2503 }
John Kessenich34fb0362016-05-03 23:17:20 -06002504
2505 if (! peekTokenClass(EHTokComma))
2506 return true;
2507
2508 return true;
2509}
2510
John Kessenich00957f82016-07-27 10:39:57 -06002511// Accept a conditional expression, which associates right-to-left,
2512// accomplished by the "true" expression calling down to lower
2513// precedence levels than this level.
2514//
2515// conditional_expression
2516// : binary_expression
2517// | binary_expression QUESTION expression COLON assignment_expression
2518//
2519bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2520{
2521 // binary_expression
2522 if (! acceptBinaryExpression(node, PlLogicalOr))
2523 return false;
2524
2525 if (! acceptTokenClass(EHTokQuestion))
2526 return true;
2527
John Kessenich7e997e22017-03-30 22:09:30 -06002528 node = parseContext.convertConditionalExpression(token.loc, node);
2529 if (node == nullptr)
2530 return false;
2531
John Kessenich00957f82016-07-27 10:39:57 -06002532 TIntermTyped* trueNode = nullptr;
2533 if (! acceptExpression(trueNode)) {
2534 expected("expression after ?");
2535 return false;
2536 }
2537 TSourceLoc loc = token.loc;
2538
2539 if (! acceptTokenClass(EHTokColon)) {
2540 expected(":");
2541 return false;
2542 }
2543
2544 TIntermTyped* falseNode = nullptr;
2545 if (! acceptAssignmentExpression(falseNode)) {
2546 expected("expression after :");
2547 return false;
2548 }
2549
2550 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2551
2552 return true;
2553}
2554
John Kessenich34fb0362016-05-03 23:17:20 -06002555// Accept a binary expression, for binary operations that
2556// associate left-to-right. This is, it is implicit, for example
2557//
2558// ((a op b) op c) op d
2559//
2560// binary_expression
2561// : expression op expression op expression ...
2562//
2563// where 'expression' is the next higher level in precedence.
2564//
2565bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2566{
2567 if (precedenceLevel > PlMul)
2568 return acceptUnaryExpression(node);
2569
2570 // assignment_expression
2571 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2572 return false;
2573
John Kessenich34fb0362016-05-03 23:17:20 -06002574 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002575 TOperator op = HlslOpMap::binary(peek());
2576 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2577 if (tokenLevel < precedenceLevel)
2578 return true;
2579
John Kessenich34fb0362016-05-03 23:17:20 -06002580 // ... op
2581 TSourceLoc loc = token.loc;
2582 advanceToken();
2583
2584 // ... expression
2585 TIntermTyped* rightNode = nullptr;
2586 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2587 expected("expression");
2588 return false;
2589 }
2590
2591 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002592 if (node == nullptr) {
2593 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2594 return false;
2595 }
John Kessenich34fb0362016-05-03 23:17:20 -06002596 } while (true);
2597}
2598
2599// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002600// : (type) unary_expression
2601// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002602// | - unary_expression
2603// | ! unary_expression
2604// | ~ unary_expression
2605// | ++ unary_expression
2606// | -- unary_expression
2607// | postfix_expression
2608//
2609bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2610{
John Kessenich1cc1a282016-06-03 16:55:49 -06002611 // (type) unary_expression
2612 // Have to look two steps ahead, because this could be, e.g., a
2613 // postfix_expression instead, since that also starts with at "(".
2614 if (acceptTokenClass(EHTokLeftParen)) {
2615 TType castType;
2616 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002617 if (acceptTokenClass(EHTokRightParen)) {
2618 // We've matched "(type)" now, get the expression to cast
2619 TSourceLoc loc = token.loc;
2620 if (! acceptUnaryExpression(node))
2621 return false;
2622
2623 // Hook it up like a constructor
2624 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2625 if (constructorFunction == nullptr) {
2626 expected("type that can be constructed");
2627 return false;
2628 }
2629 TIntermTyped* arguments = nullptr;
2630 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2631 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2632
2633 return true;
2634 } else {
2635 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2636 // the '(int' part. We must back up twice.
2637 recedeToken();
2638 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002639 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002640 } else {
2641 // This isn't a type cast, but it still started "(", so if it is a
2642 // unary expression, it can only be a postfix_expression, so try that.
2643 // Back it up first.
2644 recedeToken();
2645 return acceptPostfixExpression(node);
2646 }
2647 }
2648
2649 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002650 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002651
John Kessenich1cc1a282016-06-03 16:55:49 -06002652 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002653 if (unaryOp == EOpNull)
2654 return acceptPostfixExpression(node);
2655
2656 // op unary_expression
2657 TSourceLoc loc = token.loc;
2658 advanceToken();
2659 if (! acceptUnaryExpression(node))
2660 return false;
2661
2662 // + is a no-op
2663 if (unaryOp == EOpAdd)
2664 return true;
2665
2666 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002667
2668 // These unary ops require lvalues
2669 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2670 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002671
2672 return node != nullptr;
2673}
2674
2675// postfix_expression
2676// : LEFT_PAREN expression RIGHT_PAREN
2677// | literal
2678// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002679// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002680// | function_call
2681// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2682// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002683// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002684// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002685// | postfix_expression INC_OP
2686// | postfix_expression DEC_OP
2687//
2688bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2689{
2690 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002691 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002692
2693 // idToken will pick up either a variable or a function name in a function call
2694 HlslToken idToken;
2695
John Kessenich21472ae2016-06-04 11:46:33 -06002696 // Find something before the postfix operations, as they can't operate
2697 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002698 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002699 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002700 if (! acceptExpression(node)) {
2701 expected("expression");
2702 return false;
2703 }
2704 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002705 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002706 return false;
2707 }
John Kessenich34fb0362016-05-03 23:17:20 -06002708 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002709 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002710 } else if (acceptConstructor(node)) {
2711 // constructor (nothing else to do yet)
2712 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002713 // user-type, namespace name, variable, or function name
2714 TString* fullName = idToken.string;
2715 while (acceptTokenClass(EHTokColonColon)) {
2716 // user-type or namespace name
2717 fullName = NewPoolTString(fullName->c_str());
2718 fullName->append(parseContext.scopeMangler);
2719 if (acceptIdentifier(idToken))
2720 fullName->append(*idToken.string);
2721 else {
2722 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002723 return false;
2724 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002725 }
2726 if (! peekTokenClass(EHTokLeftParen)) {
2727 node = parseContext.handleVariable(idToken.loc, fullName);
2728 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002729 // function_call (nothing else to do yet)
2730 } else {
2731 expected("function call arguments");
2732 return false;
2733 }
John Kessenich21472ae2016-06-04 11:46:33 -06002734 } else {
2735 // nothing found, can't post operate
2736 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002737 }
2738
steve-lunarga2b01a02016-11-28 17:09:54 -07002739 // This is to guarantee we do this no matter how we get out of the stack frame.
2740 // This way there's no bug if an early return forgets to do it.
2741 struct tFinalize {
2742 tFinalize(HlslParseContext& p) : parseContext(p) { }
2743 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002744 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002745 private:
John Kessenichca71d942017-03-07 20:44:09 -07002746 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002747 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002748 } finalize(parseContext);
2749
2750 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2751 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2752 // level: hence the init and finalize. Even though in practice these must be
2753 // constants, they are parsed no matter what.
2754 parseContext.initFlattening();
2755
John Kessenich21472ae2016-06-04 11:46:33 -06002756 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002757 do {
2758 TSourceLoc loc = token.loc;
2759 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002760
John Kessenich34fb0362016-05-03 23:17:20 -06002761 // Consume only a valid post-unary operator, otherwise we are done.
2762 switch (postOp) {
2763 case EOpIndexDirectStruct:
2764 case EOpIndexIndirect:
2765 case EOpPostIncrement:
2766 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002767 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002768 advanceToken();
2769 break;
2770 default:
2771 return true;
2772 }
John Kessenich87142c72016-03-12 20:24:24 -07002773
John Kessenich34fb0362016-05-03 23:17:20 -06002774 // We have a valid post-unary operator, process it.
2775 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002776 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002777 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002778 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002779 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002780 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002781 HlslToken field;
2782 if (! acceptIdentifier(field)) {
2783 expected("swizzle or member");
2784 return false;
2785 }
LoopDawg4886f692016-06-29 10:58:58 -06002786
John Kessenich516d92d2017-03-08 20:09:03 -07002787 if (peekTokenClass(EHTokLeftParen)) {
2788 // member function
2789 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002790
John Kessenich516d92d2017-03-08 20:09:03 -07002791 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002792 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002793 expected("function parameters");
2794 return false;
2795 }
John Kessenich516d92d2017-03-08 20:09:03 -07002796 } else
2797 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002798
John Kessenich34fb0362016-05-03 23:17:20 -06002799 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002800 }
John Kessenich34fb0362016-05-03 23:17:20 -06002801 case EOpIndexIndirect:
2802 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002803 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002804 TIntermTyped* indexNode = nullptr;
2805 if (! acceptExpression(indexNode) ||
2806 ! peekTokenClass(EHTokRightBracket)) {
2807 expected("expression followed by ']'");
2808 return false;
2809 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002810 advanceToken();
2811 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2812 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002813 }
2814 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002815 // INC_OP
2816 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002817 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002818 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002819 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002820 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002821 break;
2822 default:
2823 assert(0);
2824 break;
2825 }
2826 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002827}
2828
John Kessenichd016be12016-03-13 11:24:20 -06002829// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002830// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002831//
2832bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2833{
2834 // type
2835 TType type;
2836 if (acceptType(type)) {
2837 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2838 if (constructorFunction == nullptr)
2839 return false;
2840
2841 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002842 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002843 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002844 // It's possible this is a type keyword used as an identifier. Put the token back
2845 // for later use.
2846 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002847 return false;
2848 }
2849
2850 // hook it up
2851 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2852
2853 return true;
2854 }
2855
2856 return false;
2857}
2858
John Kessenich34fb0362016-05-03 23:17:20 -06002859// The function_call identifier was already recognized, and passed in as idToken.
2860//
2861// function_call
2862// : [idToken] arguments
2863//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002864bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002865{
John Kessenich54ee28f2017-03-11 14:13:00 -07002866 // name
2867 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002868 if (baseObject == nullptr) {
2869 functionName = &name;
2870 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002871 // Built-in methods are not in the symbol table as methods, but as global functions
2872 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002873 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002874 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002875 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002876 if (! baseObject->getType().isStruct()) {
2877 expected("structure");
2878 return false;
2879 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002880 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002881 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002882 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002883 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002884 }
LoopDawg4886f692016-06-29 10:58:58 -06002885
John Kessenich54ee28f2017-03-11 14:13:00 -07002886 // function
2887 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2888
2889 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002890 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002891 if (baseObject != nullptr) {
2892 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002893 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002894 }
John Kessenich4678ca92016-05-13 09:33:42 -06002895 if (! acceptArguments(function, arguments))
2896 return false;
2897
John Kessenich54ee28f2017-03-11 14:13:00 -07002898 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002899 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002900
2901 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002902}
2903
John Kessenich87142c72016-03-12 20:24:24 -07002904// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002905// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002906//
John Kessenichd016be12016-03-13 11:24:20 -06002907// The arguments are pushed onto the 'function' argument list and
2908// onto the 'arguments' aggregate.
2909//
John Kessenich4678ca92016-05-13 09:33:42 -06002910bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002911{
John Kessenich078d7f22016-03-14 10:02:11 -06002912 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002913 if (! acceptTokenClass(EHTokLeftParen))
2914 return false;
2915
2916 do {
John Kessenichd016be12016-03-13 11:24:20 -06002917 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002918 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002919 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002920 break;
John Kessenichd016be12016-03-13 11:24:20 -06002921
2922 // hook it up
2923 parseContext.handleFunctionArgument(function, arguments, arg);
2924
John Kessenich078d7f22016-03-14 10:02:11 -06002925 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002926 if (! acceptTokenClass(EHTokComma))
2927 break;
2928 } while (true);
2929
John Kessenich078d7f22016-03-14 10:02:11 -06002930 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002931 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002932 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002933 return false;
2934 }
2935
2936 return true;
2937}
2938
2939bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2940{
2941 switch (token.tokenClass) {
2942 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002943 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002944 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002945 case EHTokUintConstant:
2946 node = intermediate.addConstantUnion(token.u, token.loc, true);
2947 break;
John Kessenich87142c72016-03-12 20:24:24 -07002948 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002949 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002950 break;
2951 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002952 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002953 break;
2954 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002955 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002956 break;
John Kessenich86f71382016-09-19 20:23:18 -06002957 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002958 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002959 break;
John Kessenich87142c72016-03-12 20:24:24 -07002960
2961 default:
2962 return false;
2963 }
2964
2965 advanceToken();
2966
2967 return true;
2968}
2969
John Kessenich5f934b02016-03-13 17:58:25 -06002970// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002971// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002972//
John Kessenich21472ae2016-06-04 11:46:33 -06002973bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002974{
John Kessenich21472ae2016-06-04 11:46:33 -06002975 TIntermAggregate* compoundStatement = nullptr;
2976
John Kessenich34fb0362016-05-03 23:17:20 -06002977 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002978 if (! acceptTokenClass(EHTokLeftBrace))
2979 return false;
2980
2981 // statement statement ...
2982 TIntermNode* statement = nullptr;
2983 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002984 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2985 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2986 branch->getFlowOp() == EOpDefault)) {
2987 // hook up individual subsequences within a switch statement
2988 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2989 compoundStatement = nullptr;
2990 } else {
2991 // hook it up to the growing compound statement
2992 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2993 }
John Kessenich5f934b02016-03-13 17:58:25 -06002994 }
John Kessenich34fb0362016-05-03 23:17:20 -06002995 if (compoundStatement)
2996 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002997
John Kessenich21472ae2016-06-04 11:46:33 -06002998 retStatement = compoundStatement;
2999
John Kessenich34fb0362016-05-03 23:17:20 -06003000 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003001 return acceptTokenClass(EHTokRightBrace);
3002}
3003
John Kessenich0d2b6de2016-06-05 11:23:11 -06003004bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3005{
3006 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003007 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003008 parseContext.popScope();
3009
3010 return result;
3011}
3012
John Kessenich077e0522016-06-09 02:02:17 -06003013bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003014{
John Kessenich077e0522016-06-09 02:02:17 -06003015 parseContext.pushScope();
3016 bool result = acceptCompoundStatement(statement);
3017 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003018
3019 return result;
3020}
3021
John Kessenich5f934b02016-03-13 17:58:25 -06003022// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003023// : attributes attributed_statement
3024//
3025// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003026// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003027// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06003028// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06003029// | declaration_statement
3030// | selection_statement
3031// | switch_statement
3032// | case_label
3033// | iteration_statement
3034// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003035//
3036bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3037{
John Kessenich21472ae2016-06-04 11:46:33 -06003038 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003039
John Kessenich21472ae2016-06-04 11:46:33 -06003040 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003041 TAttributeMap attributes;
3042 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003043
John Kessenich21472ae2016-06-04 11:46:33 -06003044 // attributed_statement
3045 switch (peek()) {
3046 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003047 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003048
John Kessenich21472ae2016-06-04 11:46:33 -06003049 case EHTokIf:
3050 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003051
John Kessenich21472ae2016-06-04 11:46:33 -06003052 case EHTokSwitch:
3053 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003054
John Kessenich21472ae2016-06-04 11:46:33 -06003055 case EHTokFor:
3056 case EHTokDo:
3057 case EHTokWhile:
3058 return acceptIterationStatement(statement);
3059
3060 case EHTokContinue:
3061 case EHTokBreak:
3062 case EHTokDiscard:
3063 case EHTokReturn:
3064 return acceptJumpStatement(statement);
3065
3066 case EHTokCase:
3067 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003068 case EHTokDefault:
3069 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003070
3071 case EHTokSemicolon:
3072 return acceptTokenClass(EHTokSemicolon);
3073
3074 case EHTokRightBrace:
3075 // Performance: not strictly necessary, but stops a bunch of hunting early,
3076 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003077 return false;
3078
John Kessenich21472ae2016-06-04 11:46:33 -06003079 default:
3080 {
3081 // declaration
3082 if (acceptDeclaration(statement))
3083 return true;
3084
3085 // expression
3086 TIntermTyped* node;
3087 if (acceptExpression(node))
3088 statement = node;
3089 else
3090 return false;
3091
3092 // SEMICOLON (following an expression)
3093 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003094 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003095 return false;
3096 }
3097 }
3098 }
3099
John Kessenich5f934b02016-03-13 17:58:25 -06003100 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003101}
3102
John Kessenich21472ae2016-06-04 11:46:33 -06003103// attributes
3104// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3105//
3106// attribute:
3107// : UNROLL
3108// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3109// | FASTOPT
3110// | ALLOW_UAV_CONDITION
3111// | BRANCH
3112// | FLATTEN
3113// | FORCECASE
3114// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003115// | DOMAIN
3116// | EARLYDEPTHSTENCIL
3117// | INSTANCE
3118// | MAXTESSFACTOR
3119// | OUTPUTCONTROLPOINTS
3120// | OUTPUTTOPOLOGY
3121// | PARTITIONING
3122// | PATCHCONSTANTFUNC
3123// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003124//
steve-lunarg1868b142016-10-20 13:07:10 -06003125void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003126{
steve-lunarg1868b142016-10-20 13:07:10 -06003127 // For now, accept the [ XXX(X) ] syntax, but drop all but
3128 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003129 // TODO: subset to correct set? Pass on?
3130 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003131 HlslToken idToken;
3132
John Kessenich0d2b6de2016-06-05 11:23:11 -06003133 // LEFT_BRACKET?
3134 if (! acceptTokenClass(EHTokLeftBracket))
3135 return;
3136
3137 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003138 if (acceptIdentifier(idToken)) {
3139 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003140 } else if (! peekTokenClass(EHTokRightBracket)) {
3141 expected("identifier");
3142 advanceToken();
3143 }
3144
steve-lunarga22f7db2016-11-11 08:17:44 -07003145 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003146
3147 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003148 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003149 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003150
John Kessenich0d2b6de2016-06-05 11:23:11 -06003151 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003152 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003153
steve-lunarga22f7db2016-11-11 08:17:44 -07003154 while (acceptAssignmentExpression(node)) {
3155 expectingExpression = false;
3156 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003157 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003158 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003159 }
3160
steve-lunarga22f7db2016-11-11 08:17:44 -07003161 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003162 if (! acceptTokenClass(EHTokRightParen))
3163 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003164
3165 // Error for partial or missing expression
3166 if (expectingExpression || expressions->getSequence().empty())
3167 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003168 }
3169
3170 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003171 if (!acceptTokenClass(EHTokRightBracket)) {
3172 expected("]");
3173 return;
3174 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003175
steve-lunarg1868b142016-10-20 13:07:10 -06003176 // Add any values we found into the attribute map. This accepts
3177 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003178 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003179 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003180}
3181
John Kessenich0d2b6de2016-06-05 11:23:11 -06003182// selection_statement
3183// : IF LEFT_PAREN expression RIGHT_PAREN statement
3184// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3185//
John Kessenich21472ae2016-06-04 11:46:33 -06003186bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3187{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003188 TSourceLoc loc = token.loc;
3189
3190 // IF
3191 if (! acceptTokenClass(EHTokIf))
3192 return false;
3193
3194 // so that something declared in the condition is scoped to the lifetimes
3195 // of the then-else statements
3196 parseContext.pushScope();
3197
3198 // LEFT_PAREN expression RIGHT_PAREN
3199 TIntermTyped* condition;
3200 if (! acceptParenExpression(condition))
3201 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003202 condition = parseContext.convertConditionalExpression(loc, condition);
3203 if (condition == nullptr)
3204 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003205
3206 // create the child statements
3207 TIntermNodePair thenElse = { nullptr, nullptr };
3208
3209 // then statement
3210 if (! acceptScopedStatement(thenElse.node1)) {
3211 expected("then statement");
3212 return false;
3213 }
3214
3215 // ELSE
3216 if (acceptTokenClass(EHTokElse)) {
3217 // else statement
3218 if (! acceptScopedStatement(thenElse.node2)) {
3219 expected("else statement");
3220 return false;
3221 }
3222 }
3223
3224 // Put the pieces together
3225 statement = intermediate.addSelection(condition, thenElse, loc);
3226 parseContext.popScope();
3227
3228 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003229}
3230
John Kessenichd02dc5d2016-07-01 00:04:11 -06003231// switch_statement
3232// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3233//
John Kessenich21472ae2016-06-04 11:46:33 -06003234bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3235{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003236 // SWITCH
3237 TSourceLoc loc = token.loc;
3238 if (! acceptTokenClass(EHTokSwitch))
3239 return false;
3240
3241 // LEFT_PAREN expression RIGHT_PAREN
3242 parseContext.pushScope();
3243 TIntermTyped* switchExpression;
3244 if (! acceptParenExpression(switchExpression)) {
3245 parseContext.popScope();
3246 return false;
3247 }
3248
3249 // compound_statement
3250 parseContext.pushSwitchSequence(new TIntermSequence);
3251 bool statementOkay = acceptCompoundStatement(statement);
3252 if (statementOkay)
3253 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3254
3255 parseContext.popSwitchSequence();
3256 parseContext.popScope();
3257
3258 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003259}
3260
John Kessenich119f8f62016-06-05 15:44:07 -06003261// iteration_statement
3262// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3263// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3264// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3265//
3266// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003267bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3268{
John Kessenich119f8f62016-06-05 15:44:07 -06003269 TSourceLoc loc = token.loc;
3270 TIntermTyped* condition = nullptr;
3271
3272 EHlslTokenClass loop = peek();
3273 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3274
3275 // WHILE or DO or FOR
3276 advanceToken();
3277
3278 switch (loop) {
3279 case EHTokWhile:
3280 // so that something declared in the condition is scoped to the lifetime
3281 // of the while sub-statement
3282 parseContext.pushScope();
3283 parseContext.nestLooping();
3284
3285 // LEFT_PAREN condition RIGHT_PAREN
3286 if (! acceptParenExpression(condition))
3287 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003288 condition = parseContext.convertConditionalExpression(loc, condition);
3289 if (condition == nullptr)
3290 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003291
3292 // statement
3293 if (! acceptScopedStatement(statement)) {
3294 expected("while sub-statement");
3295 return false;
3296 }
3297
3298 parseContext.unnestLooping();
3299 parseContext.popScope();
3300
3301 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3302
3303 return true;
3304
3305 case EHTokDo:
3306 parseContext.nestLooping();
3307
3308 if (! acceptTokenClass(EHTokLeftBrace))
3309 expected("{");
3310
3311 // statement
3312 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3313 expected("do sub-statement");
3314 return false;
3315 }
3316
3317 if (! acceptTokenClass(EHTokRightBrace))
3318 expected("}");
3319
3320 // WHILE
3321 if (! acceptTokenClass(EHTokWhile)) {
3322 expected("while");
3323 return false;
3324 }
3325
3326 // LEFT_PAREN condition RIGHT_PAREN
3327 TIntermTyped* condition;
3328 if (! acceptParenExpression(condition))
3329 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003330 condition = parseContext.convertConditionalExpression(loc, condition);
3331 if (condition == nullptr)
3332 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003333
3334 if (! acceptTokenClass(EHTokSemicolon))
3335 expected(";");
3336
3337 parseContext.unnestLooping();
3338
3339 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3340
3341 return true;
3342
3343 case EHTokFor:
3344 {
3345 // LEFT_PAREN
3346 if (! acceptTokenClass(EHTokLeftParen))
3347 expected("(");
3348
3349 // so that something declared in the condition is scoped to the lifetime
3350 // of the for sub-statement
3351 parseContext.pushScope();
3352
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003353 // initializer
3354 TIntermNode* initNode = nullptr;
3355 if (! acceptControlDeclaration(initNode)) {
3356 TIntermTyped* initExpr = nullptr;
3357 acceptExpression(initExpr);
3358 initNode = initExpr;
3359 }
3360 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003361 if (! acceptTokenClass(EHTokSemicolon))
3362 expected(";");
3363
3364 parseContext.nestLooping();
3365
3366 // condition SEMI_COLON
3367 acceptExpression(condition);
3368 if (! acceptTokenClass(EHTokSemicolon))
3369 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003370 if (condition != nullptr) {
3371 condition = parseContext.convertConditionalExpression(loc, condition);
3372 if (condition == nullptr)
3373 return false;
3374 }
John Kessenich119f8f62016-06-05 15:44:07 -06003375
3376 // iterator SEMI_COLON
3377 TIntermTyped* iterator = nullptr;
3378 acceptExpression(iterator);
3379 if (! acceptTokenClass(EHTokRightParen))
3380 expected(")");
3381
3382 // statement
3383 if (! acceptScopedStatement(statement)) {
3384 expected("for sub-statement");
3385 return false;
3386 }
3387
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003388 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003389
3390 parseContext.popScope();
3391 parseContext.unnestLooping();
3392
3393 return true;
3394 }
3395
3396 default:
3397 return false;
3398 }
John Kessenich21472ae2016-06-04 11:46:33 -06003399}
3400
3401// jump_statement
3402// : CONTINUE SEMICOLON
3403// | BREAK SEMICOLON
3404// | DISCARD SEMICOLON
3405// | RETURN SEMICOLON
3406// | RETURN expression SEMICOLON
3407//
3408bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3409{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003410 EHlslTokenClass jump = peek();
3411 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003412 case EHTokContinue:
3413 case EHTokBreak:
3414 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003415 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003416 advanceToken();
3417 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003418 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003419 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003420 return false;
3421 }
John Kessenich21472ae2016-06-04 11:46:33 -06003422
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003423 switch (jump) {
3424 case EHTokContinue:
3425 statement = intermediate.addBranch(EOpContinue, token.loc);
3426 break;
3427 case EHTokBreak:
3428 statement = intermediate.addBranch(EOpBreak, token.loc);
3429 break;
3430 case EHTokDiscard:
3431 statement = intermediate.addBranch(EOpKill, token.loc);
3432 break;
3433
3434 case EHTokReturn:
3435 {
3436 // expression
3437 TIntermTyped* node;
3438 if (acceptExpression(node)) {
3439 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003440 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003441 } else
3442 statement = intermediate.addBranch(EOpReturn, token.loc);
3443 break;
3444 }
3445
3446 default:
3447 assert(0);
3448 return false;
3449 }
3450
3451 // SEMICOLON
3452 if (! acceptTokenClass(EHTokSemicolon))
3453 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003454
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003455 return true;
3456}
John Kessenich21472ae2016-06-04 11:46:33 -06003457
John Kessenichd02dc5d2016-07-01 00:04:11 -06003458// case_label
3459// : CASE expression COLON
3460//
John Kessenich21472ae2016-06-04 11:46:33 -06003461bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3462{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003463 TSourceLoc loc = token.loc;
3464 if (! acceptTokenClass(EHTokCase))
3465 return false;
3466
3467 TIntermTyped* expression;
3468 if (! acceptExpression(expression)) {
3469 expected("case expression");
3470 return false;
3471 }
3472
3473 if (! acceptTokenClass(EHTokColon)) {
3474 expected(":");
3475 return false;
3476 }
3477
3478 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3479
3480 return true;
3481}
3482
3483// default_label
3484// : DEFAULT COLON
3485//
3486bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3487{
3488 TSourceLoc loc = token.loc;
3489 if (! acceptTokenClass(EHTokDefault))
3490 return false;
3491
3492 if (! acceptTokenClass(EHTokColon)) {
3493 expected(":");
3494 return false;
3495 }
3496
3497 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3498
3499 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003500}
3501
John Kessenich19b92ff2016-06-19 11:50:34 -06003502// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003503// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3504// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003505//
3506void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3507{
3508 arraySizes = nullptr;
3509
steve-lunarg7b211a32016-10-13 12:26:18 -06003510 // Early-out if there aren't any array dimensions
3511 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003512 return;
3513
steve-lunarg7b211a32016-10-13 12:26:18 -06003514 // 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 -06003515 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003516
3517 // Collect each array dimension.
3518 while (acceptTokenClass(EHTokLeftBracket)) {
3519 TSourceLoc loc = token.loc;
3520 TIntermTyped* sizeExpr = nullptr;
3521
John Kessenich057df292017-03-06 18:18:37 -07003522 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003523 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3524
3525 if (! acceptTokenClass(EHTokRightBracket)) {
3526 expected("]");
3527 return;
3528 }
3529
3530 if (hasArraySize) {
3531 TArraySize arraySize;
3532 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3533 arraySizes->addInnerSize(arraySize);
3534 } else {
3535 arraySizes->addInnerSize(0); // sized by initializers.
3536 }
steve-lunarg265c0612016-09-27 10:57:35 -06003537 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003538}
3539
John Kessenich630dd7d2016-06-12 23:52:12 -06003540// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003541// : COLON semantic // optional
3542// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3543// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003544// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003545// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003546//
John Kessenich854fe242017-03-02 14:30:59 -07003547// Return true if any tokens were accepted. That is,
3548// false can be returned on successfully recognizing nothing,
3549// not necessarily meaning bad syntax.
3550//
3551bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003552{
John Kessenich854fe242017-03-02 14:30:59 -07003553 bool found = false;
3554
John Kessenich630dd7d2016-06-12 23:52:12 -06003555 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003556 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003557 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003558 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003559 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003560 if (peekTokenClass(EHTokLayout))
3561 acceptLayoutQualifierList(qualifier);
3562 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003563 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003564 if (! acceptTokenClass(EHTokLeftParen)) {
3565 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003566 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003567 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003568 HlslToken locationToken;
3569 if (! acceptIdentifier(locationToken)) {
3570 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003571 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003572 }
3573 HlslToken componentToken;
3574 if (acceptTokenClass(EHTokDot)) {
3575 if (! acceptIdentifier(componentToken)) {
3576 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003577 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003578 }
3579 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003580 if (! acceptTokenClass(EHTokRightParen)) {
3581 expected(")");
3582 break;
3583 }
John Kessenich7735b942016-09-05 12:40:06 -06003584 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003585 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003586 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003587 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003588 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003589 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3590 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003591 if (! acceptTokenClass(EHTokLeftParen)) {
3592 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003593 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003594 }
John Kessenichb38f0712016-07-30 10:29:54 -06003595 HlslToken registerDesc; // for Type#
3596 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003597 if (! acceptIdentifier(registerDesc)) {
3598 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003599 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003600 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003601 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3602 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003603 // Then we didn't really see the registerDesc yet, it was
3604 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003605 profile = registerDesc;
3606 if (! acceptIdentifier(registerDesc)) {
3607 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003608 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003609 }
3610 }
John Kessenichb38f0712016-07-30 10:29:54 -06003611 int subComponent = 0;
3612 if (acceptTokenClass(EHTokLeftBracket)) {
3613 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3614 if (! peekTokenClass(EHTokIntConstant)) {
3615 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003616 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003617 }
3618 subComponent = token.i;
3619 advanceToken();
3620 if (! acceptTokenClass(EHTokRightBracket)) {
3621 expected("]");
3622 break;
3623 }
3624 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003625 // (COMMA SPACEN)opt
3626 HlslToken spaceDesc;
3627 if (acceptTokenClass(EHTokComma)) {
3628 if (! acceptIdentifier(spaceDesc)) {
3629 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003630 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003631 }
3632 }
3633 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003634 if (! acceptTokenClass(EHTokRightParen)) {
3635 expected(")");
3636 break;
3637 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003638 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003639 } else {
3640 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003641 TString semanticUpperCase = *idToken.string;
3642 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3643 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003644 }
John Kessenich854fe242017-03-02 14:30:59 -07003645 } else if (peekTokenClass(EHTokLeftAngle)) {
3646 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003647 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003648 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003649 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003650
John Kessenich630dd7d2016-06-12 23:52:12 -06003651 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003652
3653 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003654}
3655
John Kessenichb16f7e62017-03-11 19:32:47 -07003656//
3657// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3658// processing.
3659//
3660bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3661{
3662 if (! peekTokenClass(EHTokLeftBrace))
3663 return false;
3664
3665 int braceCount = 0;
3666
3667 do {
3668 switch (peek()) {
3669 case EHTokLeftBrace:
3670 ++braceCount;
3671 break;
3672 case EHTokRightBrace:
3673 --braceCount;
3674 break;
3675 case EHTokNone:
3676 // End of input before balance { } is bad...
3677 return false;
3678 default:
3679 break;
3680 }
3681
3682 tokens.push_back(token);
3683 advanceToken();
3684 } while (braceCount > 0);
3685
3686 return true;
3687}
3688
John Kesseniche01a9bc2016-03-12 20:11:22 -07003689} // end namespace glslang