blob: 674dcac5ede516a1709a4138887bf42d1564e265 [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-lunargd3947d22017-03-19 12:40:12 -0600614 // Propagate sampler readonly qualifier for buffers
615 if (type.getBasicType() == EbtSampler)
616 qualifier.readonly = type.getQualifier().readonly;
617
steve-lunarg5da1f032017-02-12 17:50:28 -0700618 if (type.getQualifier().storage == EvqVaryingOut ||
619 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700620 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700621 qualifier.readonly = type.getQualifier().readonly;
622 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700623
624 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600625 }
John Kessenich87142c72016-03-12 20:24:24 -0700626
627 return true;
628}
629
John Kessenich630dd7d2016-06-12 23:52:12 -0600630// type_qualifier
631// : qualifier qualifier ...
632//
633// Zero or more of these, so this can't return false.
634//
John Kessenichb9e39122016-08-17 10:22:08 -0600635bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700636{
John Kessenich630dd7d2016-06-12 23:52:12 -0600637 do {
638 switch (peek()) {
639 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600640 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600641 break;
642 case EHTokExtern:
643 // TODO: no meaning in glslang?
644 break;
645 case EHTokShared:
646 // TODO: hint
647 break;
648 case EHTokGroupShared:
649 qualifier.storage = EvqShared;
650 break;
651 case EHTokUniform:
652 qualifier.storage = EvqUniform;
653 break;
654 case EHTokConst:
655 qualifier.storage = EvqConst;
656 break;
657 case EHTokVolatile:
658 qualifier.volatil = true;
659 break;
660 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600661 qualifier.smooth = true;
662 break;
663 case EHTokCentroid:
664 qualifier.centroid = true;
665 break;
666 case EHTokNointerpolation:
667 qualifier.flat = true;
668 break;
669 case EHTokNoperspective:
670 qualifier.nopersp = true;
671 break;
672 case EHTokSample:
673 qualifier.sample = true;
674 break;
675 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600676 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600677 break;
678 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600679 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600680 break;
681 case EHTokPrecise:
682 qualifier.noContraction = true;
683 break;
LoopDawg9249c702016-07-12 20:44:32 -0600684 case EHTokIn:
685 qualifier.storage = EvqIn;
686 break;
687 case EHTokOut:
688 qualifier.storage = EvqOut;
689 break;
690 case EHTokInOut:
691 qualifier.storage = EvqInOut;
692 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600693 case EHTokLayout:
694 if (! acceptLayoutQualifierList(qualifier))
695 return false;
696 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700697 case EHTokGloballyCoherent:
698 qualifier.coherent = true;
699 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600700 case EHTokInline:
701 // TODO: map this to SPIR-V function control
702 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700703
704 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
705 // for output variables.
706 case EHTokPoint:
707 qualifier.storage = EvqIn;
708 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
709 return false;
710 break;
711 case EHTokLine:
712 qualifier.storage = EvqIn;
713 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
714 return false;
715 break;
716 case EHTokTriangle:
717 qualifier.storage = EvqIn;
718 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
719 return false;
720 break;
721 case EHTokLineAdj:
722 qualifier.storage = EvqIn;
723 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
724 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700725 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700726 case EHTokTriangleAdj:
727 qualifier.storage = EvqIn;
728 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
729 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700730 break;
731
John Kessenich630dd7d2016-06-12 23:52:12 -0600732 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600733 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600734 }
735 advanceToken();
736 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700737}
738
John Kessenichb9e39122016-08-17 10:22:08 -0600739// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600740// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600741//
742// layout_qualifier
743// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600744// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600745//
746// Zero or more of these, so this can't return false.
747//
748bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
749{
750 if (! acceptTokenClass(EHTokLayout))
751 return false;
752
753 // LEFT_PAREN
754 if (! acceptTokenClass(EHTokLeftParen))
755 return false;
756
757 do {
758 // identifier
759 HlslToken idToken;
760 if (! acceptIdentifier(idToken))
761 break;
762
763 // EQUAL expression
764 if (acceptTokenClass(EHTokAssign)) {
765 TIntermTyped* expr;
766 if (! acceptConditionalExpression(expr)) {
767 expected("expression");
768 return false;
769 }
770 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
771 } else
772 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
773
774 // COMMA
775 if (! acceptTokenClass(EHTokComma))
776 break;
777 } while (true);
778
779 // RIGHT_PAREN
780 if (! acceptTokenClass(EHTokRightParen)) {
781 expected(")");
782 return false;
783 }
784
785 return true;
786}
787
LoopDawg6daaa4f2016-06-23 19:13:48 -0600788// template_type
789// : FLOAT
790// | DOUBLE
791// | INT
792// | DWORD
793// | UINT
794// | BOOL
795//
steve-lunargf49cdf42016-11-17 15:04:20 -0700796bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600797{
798 switch (peek()) {
799 case EHTokFloat:
800 basicType = EbtFloat;
801 break;
802 case EHTokDouble:
803 basicType = EbtDouble;
804 break;
805 case EHTokInt:
806 case EHTokDword:
807 basicType = EbtInt;
808 break;
809 case EHTokUint:
810 basicType = EbtUint;
811 break;
812 case EHTokBool:
813 basicType = EbtBool;
814 break;
815 default:
816 return false;
817 }
818
819 advanceToken();
820
821 return true;
822}
823
824// vector_template_type
825// : VECTOR
826// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
827//
828bool HlslGrammar::acceptVectorTemplateType(TType& type)
829{
830 if (! acceptTokenClass(EHTokVector))
831 return false;
832
833 if (! acceptTokenClass(EHTokLeftAngle)) {
834 // in HLSL, 'vector' alone means float4.
835 new(&type) TType(EbtFloat, EvqTemporary, 4);
836 return true;
837 }
838
839 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700840 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600841 expected("scalar type");
842 return false;
843 }
844
845 // COMMA
846 if (! acceptTokenClass(EHTokComma)) {
847 expected(",");
848 return false;
849 }
850
851 // integer
852 if (! peekTokenClass(EHTokIntConstant)) {
853 expected("literal integer");
854 return false;
855 }
856
857 TIntermTyped* vecSize;
858 if (! acceptLiteral(vecSize))
859 return false;
860
861 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
862
863 new(&type) TType(basicType, EvqTemporary, vecSizeI);
864
865 if (vecSizeI == 1)
866 type.makeVector();
867
868 if (!acceptTokenClass(EHTokRightAngle)) {
869 expected("right angle bracket");
870 return false;
871 }
872
873 return true;
874}
875
876// matrix_template_type
877// : MATRIX
878// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
879//
880bool HlslGrammar::acceptMatrixTemplateType(TType& type)
881{
882 if (! acceptTokenClass(EHTokMatrix))
883 return false;
884
885 if (! acceptTokenClass(EHTokLeftAngle)) {
886 // in HLSL, 'matrix' alone means float4x4.
887 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
888 return true;
889 }
890
891 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700892 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600893 expected("scalar type");
894 return false;
895 }
896
897 // COMMA
898 if (! acceptTokenClass(EHTokComma)) {
899 expected(",");
900 return false;
901 }
902
903 // integer rows
904 if (! peekTokenClass(EHTokIntConstant)) {
905 expected("literal integer");
906 return false;
907 }
908
909 TIntermTyped* rows;
910 if (! acceptLiteral(rows))
911 return false;
912
913 // COMMA
914 if (! acceptTokenClass(EHTokComma)) {
915 expected(",");
916 return false;
917 }
John Kessenichecba76f2017-01-06 00:34:48 -0700918
LoopDawg6daaa4f2016-06-23 19:13:48 -0600919 // integer cols
920 if (! peekTokenClass(EHTokIntConstant)) {
921 expected("literal integer");
922 return false;
923 }
924
925 TIntermTyped* cols;
926 if (! acceptLiteral(cols))
927 return false;
928
929 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600930 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
931 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600932
933 if (!acceptTokenClass(EHTokRightAngle)) {
934 expected("right angle bracket");
935 return false;
936 }
937
938 return true;
939}
940
steve-lunargf49cdf42016-11-17 15:04:20 -0700941// layout_geometry
942// : LINESTREAM
943// | POINTSTREAM
944// | TRIANGLESTREAM
945//
946bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
947{
948 // read geometry type
949 const EHlslTokenClass geometryType = peek();
950
951 switch (geometryType) {
952 case EHTokPointStream: geometry = ElgPoints; break;
953 case EHTokLineStream: geometry = ElgLineStrip; break;
954 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
955 default:
956 return false; // not a layout geometry
957 }
958
959 advanceToken(); // consume the layout keyword
960 return true;
961}
962
steve-lunarg858c9282017-01-07 08:54:10 -0700963// tessellation_decl_type
964// : INPUTPATCH
965// | OUTPUTPATCH
966//
967bool HlslGrammar::acceptTessellationDeclType()
968{
969 // read geometry type
970 const EHlslTokenClass tessType = peek();
971
972 switch (tessType) {
973 case EHTokInputPatch: break;
974 case EHTokOutputPatch: break;
975 default:
976 return false; // not a tessellation decl
977 }
978
979 advanceToken(); // consume the keyword
980 return true;
981}
982
983// tessellation_patch_template_type
984// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
985//
986bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
987{
988 if (! acceptTessellationDeclType())
989 return false;
990
991 if (! acceptTokenClass(EHTokLeftAngle))
992 return false;
993
994 if (! acceptType(type)) {
995 expected("tessellation patch type");
996 return false;
997 }
998
999 if (! acceptTokenClass(EHTokComma))
1000 return false;
1001
1002 // integer size
1003 if (! peekTokenClass(EHTokIntConstant)) {
1004 expected("literal integer");
1005 return false;
1006 }
1007
1008 TIntermTyped* size;
1009 if (! acceptLiteral(size))
1010 return false;
1011
1012 TArraySizes* arraySizes = new TArraySizes;
1013 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
1014 type.newArraySizes(*arraySizes);
1015
1016 if (! acceptTokenClass(EHTokRightAngle)) {
1017 expected("right angle bracket");
1018 return false;
1019 }
1020
1021 return true;
1022}
1023
steve-lunargf49cdf42016-11-17 15:04:20 -07001024// stream_out_template_type
1025// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
1026//
1027bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
1028{
1029 geometry = ElgNone;
1030
1031 if (! acceptOutputPrimitiveGeometry(geometry))
1032 return false;
1033
1034 if (! acceptTokenClass(EHTokLeftAngle))
1035 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001036
steve-lunargf49cdf42016-11-17 15:04:20 -07001037 if (! acceptType(type)) {
1038 expected("stream output type");
1039 return false;
1040 }
1041
1042 type.getQualifier().storage = EvqVaryingOut;
1043
1044 if (! acceptTokenClass(EHTokRightAngle)) {
1045 expected("right angle bracket");
1046 return false;
1047 }
1048
1049 return true;
1050}
John Kessenichecba76f2017-01-06 00:34:48 -07001051
John Kessenicha1e2d492016-09-20 13:22:58 -06001052// annotations
1053// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -06001054//
John Kessenicha1e2d492016-09-20 13:22:58 -06001055bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -06001056{
John Kessenicha1e2d492016-09-20 13:22:58 -06001057 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -06001058 return false;
1059
John Kessenicha1e2d492016-09-20 13:22:58 -06001060 // note that we are nesting a name space
1061 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -06001062
1063 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
1064 do {
1065 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
1066 while (acceptTokenClass(EHTokSemicolon))
1067 ;
1068
1069 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001070 break;
John Kessenich86f71382016-09-19 20:23:18 -06001071
1072 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001073 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001074 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001075 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001076 return false;
1077 }
1078 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001079
1080 parseContext.unnestAnnotations();
1081 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001082}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001083
LoopDawg4886f692016-06-29 10:58:58 -06001084// sampler_type
1085// : SAMPLER
1086// | SAMPLER1D
1087// | SAMPLER2D
1088// | SAMPLER3D
1089// | SAMPLERCUBE
1090// | SAMPLERSTATE
1091// | SAMPLERCOMPARISONSTATE
1092bool HlslGrammar::acceptSamplerType(TType& type)
1093{
1094 // read sampler type
1095 const EHlslTokenClass samplerType = peek();
1096
LoopDawga78b0292016-07-19 14:28:05 -06001097 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001098 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001099
LoopDawga78b0292016-07-19 14:28:05 -06001100 bool isShadow = false;
1101
LoopDawg4886f692016-06-29 10:58:58 -06001102 switch (samplerType) {
1103 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001104 case EHTokSampler1d: /*dim = Esd1D*/; break;
1105 case EHTokSampler2d: /*dim = Esd2D*/; break;
1106 case EHTokSampler3d: /*dim = Esd3D*/; break;
1107 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001108 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001109 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001110 default:
1111 return false; // not a sampler declaration
1112 }
1113
1114 advanceToken(); // consume the sampler type keyword
1115
1116 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001117
1118 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001119 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001120
1121 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1122
1123 return true;
1124}
1125
1126// texture_type
1127// | BUFFER
1128// | TEXTURE1D
1129// | TEXTURE1DARRAY
1130// | TEXTURE2D
1131// | TEXTURE2DARRAY
1132// | TEXTURE3D
1133// | TEXTURECUBE
1134// | TEXTURECUBEARRAY
1135// | TEXTURE2DMS
1136// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001137// | RWBUFFER
1138// | RWTEXTURE1D
1139// | RWTEXTURE1DARRAY
1140// | RWTEXTURE2D
1141// | RWTEXTURE2DARRAY
1142// | RWTEXTURE3D
1143
LoopDawg4886f692016-06-29 10:58:58 -06001144bool HlslGrammar::acceptTextureType(TType& type)
1145{
1146 const EHlslTokenClass textureType = peek();
1147
1148 TSamplerDim dim = EsdNone;
1149 bool array = false;
1150 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001151 bool image = false;
steve-lunargcf2e7272017-03-17 13:19:42 -06001152 bool readonly = false;
LoopDawg4886f692016-06-29 10:58:58 -06001153
1154 switch (textureType) {
steve-lunargcf2e7272017-03-17 13:19:42 -06001155 case EHTokTexture1d: dim = Esd1D; break;
1156 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1157 case EHTokTexture2d: dim = Esd2D; break;
1158 case EHTokTexture2darray: dim = Esd2D; array = true; break;
1159 case EHTokTexture3d: dim = Esd3D; break;
1160 case EHTokTextureCube: dim = EsdCube; break;
1161 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1162 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1163 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
1164 case EHTokBuffer: dim = EsdBuffer; readonly=true; image=true; break;
1165 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1166 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1167 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1168 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1169 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1170 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001171 default:
1172 return false; // not a texture declaration
1173 }
1174
1175 advanceToken(); // consume the texture object keyword
1176
1177 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001178
LoopDawg4886f692016-06-29 10:58:58 -06001179 TIntermTyped* msCount = nullptr;
1180
steve-lunargbb0183f2016-10-04 16:58:14 -06001181 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001182 if (acceptTokenClass(EHTokLeftAngle)) {
1183 if (! acceptType(txType)) {
1184 expected("scalar or vector type");
1185 return false;
1186 }
1187
1188 const TBasicType basicRetType = txType.getBasicType() ;
1189
1190 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1191 unimplemented("basic type in texture");
1192 return false;
1193 }
1194
steve-lunargd53f7172016-07-27 15:46:48 -06001195 // Buffers can handle small mats if they fit in 4 components
1196 if (dim == EsdBuffer && txType.isMatrix()) {
1197 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1198 expected("components < 4 in matrix buffer type");
1199 return false;
1200 }
1201
1202 // TODO: except we don't handle it yet...
1203 unimplemented("matrix type in buffer");
1204 return false;
1205 }
1206
LoopDawg4886f692016-06-29 10:58:58 -06001207 if (!txType.isScalar() && !txType.isVector()) {
1208 expected("scalar or vector type");
1209 return false;
1210 }
1211
LoopDawg4886f692016-06-29 10:58:58 -06001212 if (ms && acceptTokenClass(EHTokComma)) {
1213 // read sample count for multisample types, if given
1214 if (! peekTokenClass(EHTokIntConstant)) {
1215 expected("multisample count");
1216 return false;
1217 }
1218
1219 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1220 return false;
1221 }
1222
1223 if (! acceptTokenClass(EHTokRightAngle)) {
1224 expected("right angle bracket");
1225 return false;
1226 }
1227 } else if (ms) {
1228 expected("texture type for multisample");
1229 return false;
steve-lunargcf2e7272017-03-17 13:19:42 -06001230 } else if (image && !readonly) {
steve-lunargbb0183f2016-10-04 16:58:14 -06001231 expected("type for RWTexture/RWBuffer");
1232 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001233 }
1234
1235 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001236 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001237
1238 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001239 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001240
steve-lunarg4f2da272016-10-10 15:24:57 -06001241 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1242 if (image || dim == EsdBuffer)
1243 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001244
1245 // Non-image Buffers are combined
1246 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001247 sampler.set(txType.getBasicType(), dim, array);
1248 } else {
1249 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001250 if (image) {
1251 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1252 } else {
1253 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1254 }
steve-lunargd53f7172016-07-27 15:46:48 -06001255 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001256
1257 // Remember the declared vector size.
1258 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001259
LoopDawg4886f692016-06-29 10:58:58 -06001260 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1261
LoopDawg4886f692016-06-29 10:58:58 -06001262 type.getQualifier().layoutFormat = format;
steve-lunargcf2e7272017-03-17 13:19:42 -06001263 type.getQualifier().readonly = readonly;
LoopDawg4886f692016-06-29 10:58:58 -06001264
1265 return true;
1266}
1267
John Kessenich87142c72016-03-12 20:24:24 -07001268// If token is for a type, update 'type' with the type information,
1269// and return true and advance.
1270// Otherwise, return false, and don't advance
1271bool HlslGrammar::acceptType(TType& type)
1272{
John Kessenich54ee28f2017-03-11 14:13:00 -07001273 TIntermNode* nodeList = nullptr;
1274 return acceptType(type, nodeList);
1275}
1276bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1277{
steve-lunarg3226b082016-10-26 19:18:55 -06001278 // Basic types for min* types, broken out here in case of future
1279 // changes, e.g, to use native halfs.
1280 static const TBasicType min16float_bt = EbtFloat;
1281 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001282 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001283 static const TBasicType min16int_bt = EbtInt;
1284 static const TBasicType min12int_bt = EbtInt;
1285 static const TBasicType min16uint_bt = EbtUint;
1286
John Kessenich9c86c6a2016-05-03 22:49:24 -06001287 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001288 case EHTokVector:
1289 return acceptVectorTemplateType(type);
1290 break;
1291
1292 case EHTokMatrix:
1293 return acceptMatrixTemplateType(type);
1294 break;
1295
steve-lunargf49cdf42016-11-17 15:04:20 -07001296 case EHTokPointStream: // fall through
1297 case EHTokLineStream: // ...
1298 case EHTokTriangleStream: // ...
1299 {
1300 TLayoutGeometry geometry;
1301 if (! acceptStreamOutTemplateType(type, geometry))
1302 return false;
1303
1304 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1305 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001306
steve-lunargf49cdf42016-11-17 15:04:20 -07001307 return true;
1308 }
1309
steve-lunarg858c9282017-01-07 08:54:10 -07001310 case EHTokInputPatch: // fall through
1311 case EHTokOutputPatch: // ...
1312 {
1313 if (! acceptTessellationPatchTemplateType(type))
1314 return false;
1315
1316 return true;
1317 }
1318
LoopDawg4886f692016-06-29 10:58:58 -06001319 case EHTokSampler: // fall through
1320 case EHTokSampler1d: // ...
1321 case EHTokSampler2d: // ...
1322 case EHTokSampler3d: // ...
1323 case EHTokSamplerCube: // ...
1324 case EHTokSamplerState: // ...
1325 case EHTokSamplerComparisonState: // ...
1326 return acceptSamplerType(type);
1327 break;
1328
1329 case EHTokBuffer: // fall through
1330 case EHTokTexture1d: // ...
1331 case EHTokTexture1darray: // ...
1332 case EHTokTexture2d: // ...
1333 case EHTokTexture2darray: // ...
1334 case EHTokTexture3d: // ...
1335 case EHTokTextureCube: // ...
1336 case EHTokTextureCubearray: // ...
1337 case EHTokTexture2DMS: // ...
1338 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001339 case EHTokRWTexture1d: // ...
1340 case EHTokRWTexture1darray: // ...
1341 case EHTokRWTexture2d: // ...
1342 case EHTokRWTexture2darray: // ...
1343 case EHTokRWTexture3d: // ...
1344 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001345 return acceptTextureType(type);
1346 break;
1347
steve-lunarg5da1f032017-02-12 17:50:28 -07001348 case EHTokAppendStructuredBuffer:
1349 case EHTokByteAddressBuffer:
1350 case EHTokConsumeStructuredBuffer:
1351 case EHTokRWByteAddressBuffer:
1352 case EHTokRWStructuredBuffer:
1353 case EHTokStructuredBuffer:
1354 return acceptStructBufferType(type);
1355 break;
1356
John Kessenich27ffb292017-03-03 17:01:01 -07001357 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001358 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001359 case EHTokCBuffer:
1360 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001361 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001362
1363 case EHTokIdentifier:
1364 // An identifier could be for a user-defined type.
1365 // Note we cache the symbol table lookup, to save for a later rule
1366 // when this is not a type.
John Kessenichf4ba25e2017-03-21 18:35:04 -06001367 if (parseContext.lookupUserType(*token.string, type) != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001368 advanceToken();
1369 return true;
1370 } else
1371 return false;
1372
John Kessenich71351de2016-06-08 12:50:56 -06001373 case EHTokVoid:
1374 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001375 break;
John Kessenich71351de2016-06-08 12:50:56 -06001376
John Kessenicha1e2d492016-09-20 13:22:58 -06001377 case EHTokString:
1378 new(&type) TType(EbtString);
1379 break;
1380
John Kessenich87142c72016-03-12 20:24:24 -07001381 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001382 new(&type) TType(EbtFloat);
1383 break;
John Kessenich87142c72016-03-12 20:24:24 -07001384 case EHTokFloat1:
1385 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001386 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001387 break;
John Kessenich87142c72016-03-12 20:24:24 -07001388 case EHTokFloat2:
1389 new(&type) TType(EbtFloat, EvqTemporary, 2);
1390 break;
1391 case EHTokFloat3:
1392 new(&type) TType(EbtFloat, EvqTemporary, 3);
1393 break;
1394 case EHTokFloat4:
1395 new(&type) TType(EbtFloat, EvqTemporary, 4);
1396 break;
1397
John Kessenich71351de2016-06-08 12:50:56 -06001398 case EHTokDouble:
1399 new(&type) TType(EbtDouble);
1400 break;
1401 case EHTokDouble1:
1402 new(&type) TType(EbtDouble);
1403 type.makeVector();
1404 break;
1405 case EHTokDouble2:
1406 new(&type) TType(EbtDouble, EvqTemporary, 2);
1407 break;
1408 case EHTokDouble3:
1409 new(&type) TType(EbtDouble, EvqTemporary, 3);
1410 break;
1411 case EHTokDouble4:
1412 new(&type) TType(EbtDouble, EvqTemporary, 4);
1413 break;
1414
1415 case EHTokInt:
1416 case EHTokDword:
1417 new(&type) TType(EbtInt);
1418 break;
1419 case EHTokInt1:
1420 new(&type) TType(EbtInt);
1421 type.makeVector();
1422 break;
John Kessenich87142c72016-03-12 20:24:24 -07001423 case EHTokInt2:
1424 new(&type) TType(EbtInt, EvqTemporary, 2);
1425 break;
1426 case EHTokInt3:
1427 new(&type) TType(EbtInt, EvqTemporary, 3);
1428 break;
1429 case EHTokInt4:
1430 new(&type) TType(EbtInt, EvqTemporary, 4);
1431 break;
1432
John Kessenich71351de2016-06-08 12:50:56 -06001433 case EHTokUint:
1434 new(&type) TType(EbtUint);
1435 break;
1436 case EHTokUint1:
1437 new(&type) TType(EbtUint);
1438 type.makeVector();
1439 break;
1440 case EHTokUint2:
1441 new(&type) TType(EbtUint, EvqTemporary, 2);
1442 break;
1443 case EHTokUint3:
1444 new(&type) TType(EbtUint, EvqTemporary, 3);
1445 break;
1446 case EHTokUint4:
1447 new(&type) TType(EbtUint, EvqTemporary, 4);
1448 break;
1449
1450 case EHTokBool:
1451 new(&type) TType(EbtBool);
1452 break;
1453 case EHTokBool1:
1454 new(&type) TType(EbtBool);
1455 type.makeVector();
1456 break;
John Kessenich87142c72016-03-12 20:24:24 -07001457 case EHTokBool2:
1458 new(&type) TType(EbtBool, EvqTemporary, 2);
1459 break;
1460 case EHTokBool3:
1461 new(&type) TType(EbtBool, EvqTemporary, 3);
1462 break;
1463 case EHTokBool4:
1464 new(&type) TType(EbtBool, EvqTemporary, 4);
1465 break;
1466
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001467 case EHTokHalf:
1468 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1469 break;
1470 case EHTokHalf1:
1471 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1472 type.makeVector();
1473 break;
1474 case EHTokHalf2:
1475 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1476 break;
1477 case EHTokHalf3:
1478 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1479 break;
1480 case EHTokHalf4:
1481 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1482 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001483
steve-lunarg3226b082016-10-26 19:18:55 -06001484 case EHTokMin16float:
1485 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1486 break;
1487 case EHTokMin16float1:
1488 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1489 type.makeVector();
1490 break;
1491 case EHTokMin16float2:
1492 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1493 break;
1494 case EHTokMin16float3:
1495 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1496 break;
1497 case EHTokMin16float4:
1498 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1499 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001500
steve-lunarg3226b082016-10-26 19:18:55 -06001501 case EHTokMin10float:
1502 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1503 break;
1504 case EHTokMin10float1:
1505 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1506 type.makeVector();
1507 break;
1508 case EHTokMin10float2:
1509 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1510 break;
1511 case EHTokMin10float3:
1512 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1513 break;
1514 case EHTokMin10float4:
1515 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1516 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001517
steve-lunarg3226b082016-10-26 19:18:55 -06001518 case EHTokMin16int:
1519 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1520 break;
1521 case EHTokMin16int1:
1522 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1523 type.makeVector();
1524 break;
1525 case EHTokMin16int2:
1526 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1527 break;
1528 case EHTokMin16int3:
1529 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1530 break;
1531 case EHTokMin16int4:
1532 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1533 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001534
steve-lunarg3226b082016-10-26 19:18:55 -06001535 case EHTokMin12int:
1536 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1537 break;
1538 case EHTokMin12int1:
1539 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1540 type.makeVector();
1541 break;
1542 case EHTokMin12int2:
1543 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1544 break;
1545 case EHTokMin12int3:
1546 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1547 break;
1548 case EHTokMin12int4:
1549 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1550 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001551
steve-lunarg3226b082016-10-26 19:18:55 -06001552 case EHTokMin16uint:
1553 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1554 break;
1555 case EHTokMin16uint1:
1556 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1557 type.makeVector();
1558 break;
1559 case EHTokMin16uint2:
1560 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1561 break;
1562 case EHTokMin16uint3:
1563 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1564 break;
1565 case EHTokMin16uint4:
1566 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1567 break;
1568
John Kessenich0133c122016-05-20 12:17:26 -06001569 case EHTokInt1x1:
1570 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1571 break;
1572 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001573 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001574 break;
1575 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001576 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001577 break;
1578 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001579 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001580 break;
1581 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001582 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001583 break;
1584 case EHTokInt2x2:
1585 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1586 break;
1587 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001588 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001589 break;
1590 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001591 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001592 break;
1593 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001594 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001595 break;
1596 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001597 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001598 break;
1599 case EHTokInt3x3:
1600 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1601 break;
1602 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001603 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001604 break;
1605 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001606 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001607 break;
1608 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001609 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001610 break;
1611 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001612 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001613 break;
1614 case EHTokInt4x4:
1615 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1616 break;
1617
John Kessenich71351de2016-06-08 12:50:56 -06001618 case EHTokUint1x1:
1619 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1620 break;
1621 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001622 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001623 break;
1624 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001625 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001626 break;
1627 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001628 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001629 break;
1630 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001631 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001632 break;
1633 case EHTokUint2x2:
1634 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1635 break;
1636 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001637 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001638 break;
1639 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001640 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001641 break;
1642 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001643 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001644 break;
1645 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001646 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001647 break;
1648 case EHTokUint3x3:
1649 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1650 break;
1651 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001652 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001653 break;
1654 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001655 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001656 break;
1657 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001658 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001659 break;
1660 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001661 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001662 break;
1663 case EHTokUint4x4:
1664 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1665 break;
1666
1667 case EHTokBool1x1:
1668 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1669 break;
1670 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001671 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001672 break;
1673 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001674 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001675 break;
1676 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001677 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001678 break;
1679 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001680 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001681 break;
1682 case EHTokBool2x2:
1683 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1684 break;
1685 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001686 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001687 break;
1688 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001689 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001690 break;
1691 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001692 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001693 break;
1694 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001695 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001696 break;
1697 case EHTokBool3x3:
1698 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1699 break;
1700 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001701 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001702 break;
1703 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001704 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001705 break;
1706 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001707 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001708 break;
1709 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001710 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001711 break;
1712 case EHTokBool4x4:
1713 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1714 break;
1715
John Kessenich0133c122016-05-20 12:17:26 -06001716 case EHTokFloat1x1:
1717 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1718 break;
1719 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001720 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001721 break;
1722 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001723 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001724 break;
1725 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001726 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001727 break;
1728 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001729 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001730 break;
John Kessenich87142c72016-03-12 20:24:24 -07001731 case EHTokFloat2x2:
1732 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1733 break;
1734 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001735 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001736 break;
1737 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001738 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001739 break;
John Kessenich0133c122016-05-20 12:17:26 -06001740 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001741 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001742 break;
John Kessenich87142c72016-03-12 20:24:24 -07001743 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001744 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001745 break;
1746 case EHTokFloat3x3:
1747 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1748 break;
1749 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001750 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001751 break;
John Kessenich0133c122016-05-20 12:17:26 -06001752 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001753 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001754 break;
John Kessenich87142c72016-03-12 20:24:24 -07001755 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001756 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001757 break;
1758 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001759 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001760 break;
1761 case EHTokFloat4x4:
1762 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1763 break;
1764
John Kessenich0133c122016-05-20 12:17:26 -06001765 case EHTokDouble1x1:
1766 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1767 break;
1768 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001769 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001770 break;
1771 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001772 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001773 break;
1774 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001775 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001776 break;
1777 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001778 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001779 break;
1780 case EHTokDouble2x2:
1781 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1782 break;
1783 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001784 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001785 break;
1786 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001787 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001788 break;
1789 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001790 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001791 break;
1792 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001793 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001794 break;
1795 case EHTokDouble3x3:
1796 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1797 break;
1798 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001799 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001800 break;
1801 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001802 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001803 break;
1804 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001805 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001806 break;
1807 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001808 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001809 break;
1810 case EHTokDouble4x4:
1811 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1812 break;
1813
John Kessenich87142c72016-03-12 20:24:24 -07001814 default:
1815 return false;
1816 }
1817
1818 advanceToken();
1819
1820 return true;
1821}
1822
John Kesseniche6e74942016-06-11 16:43:14 -06001823// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001824// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1825// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001826// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001827//
1828// struct_type
1829// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001830// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001831// | CBUFFER
1832// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001833//
John Kessenich54ee28f2017-03-11 14:13:00 -07001834bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001835{
John Kessenichb804de62016-09-05 12:19:18 -06001836 // This storage qualifier will tell us whether it's an AST
1837 // block type or just a generic structure type.
1838 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001839
1840 // CBUFFER
1841 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001842 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001843 // TBUFFER
1844 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001845 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001846 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001847 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001848 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001849 return false;
1850
1851 // IDENTIFIER
1852 TString structName = "";
1853 if (peekTokenClass(EHTokIdentifier)) {
1854 structName = *token.string;
1855 advanceToken();
1856 }
1857
John Kessenich3d157c52016-07-25 16:05:33 -06001858 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001859 TQualifier postDeclQualifier;
1860 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001861 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001862
John Kessenichf3d88bd2017-03-19 12:24:29 -06001863 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001864 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001865 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001866 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1867 // struct_type IDENTIFIER
1868 return true;
1869 } else {
1870 expected("{");
1871 return false;
1872 }
John Kesseniche6e74942016-06-11 16:43:14 -06001873 }
1874
John Kessenichf3d88bd2017-03-19 12:24:29 -06001875
John Kesseniche6e74942016-06-11 16:43:14 -06001876 // struct_declaration_list
1877 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001878 // Save each member function so they can be processed after we have a fully formed 'this'.
1879 TVector<TFunctionDeclarator> functionDeclarators;
1880
1881 parseContext.pushNamespace(structName);
John Kessenichaa3c64c2017-03-28 09:52:38 -06001882 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, functionDeclarators);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001883 parseContext.popNamespace();
1884
1885 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001886 expected("struct member declarations");
1887 return false;
1888 }
1889
1890 // RIGHT_BRACE
1891 if (! acceptTokenClass(EHTokRightBrace)) {
1892 expected("}");
1893 return false;
1894 }
1895
1896 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001897 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001898 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001899 else {
John Kessenich7735b942016-09-05 12:40:06 -06001900 postDeclQualifier.storage = storageQualifier;
1901 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001902 }
John Kesseniche6e74942016-06-11 16:43:14 -06001903
John Kessenich727b3742017-02-03 17:57:55 -07001904 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001905
John Kessenich4960baa2017-03-19 18:09:59 -06001906 // For member functions: now that we know the type of 'this', go back and
1907 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1908 // - parse the functions, their tokens were saved for deferred parsing (now)
1909 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1910 // update signature
1911 if (functionDeclarators[b].function->hasImplicitThis())
John Kessenich37789792017-03-21 23:56:40 -06001912 functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName);
John Kessenich4960baa2017-03-19 18:09:59 -06001913 }
1914
John Kessenichf3d88bd2017-03-19 12:24:29 -06001915 // All member functions get parsed inside the class/struct namespace and with the
1916 // class/struct members in a symbol-table level.
1917 parseContext.pushNamespace(structName);
John Kessenich37789792017-03-21 23:56:40 -06001918 parseContext.pushThisScope(type);
John Kessenichf3d88bd2017-03-19 12:24:29 -06001919 bool deferredSuccess = true;
1920 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1921 // parse body
1922 pushTokenStream(functionDeclarators[b].body);
1923 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1924 deferredSuccess = false;
1925 popTokenStream();
1926 }
John Kessenich37789792017-03-21 23:56:40 -06001927 parseContext.popThisScope();
John Kessenichf3d88bd2017-03-19 12:24:29 -06001928 parseContext.popNamespace();
1929
1930 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001931}
1932
steve-lunarg5da1f032017-02-12 17:50:28 -07001933// struct_buffer
1934// : APPENDSTRUCTUREDBUFFER
1935// | BYTEADDRESSBUFFER
1936// | CONSUMESTRUCTUREDBUFFER
1937// | RWBYTEADDRESSBUFFER
1938// | RWSTRUCTUREDBUFFER
1939// | STRUCTUREDBUFFER
1940bool HlslGrammar::acceptStructBufferType(TType& type)
1941{
1942 const EHlslTokenClass structBuffType = peek();
1943
1944 // TODO: globallycoherent
1945 bool hasTemplateType = true;
1946 bool readonly = false;
1947
1948 TStorageQualifier storage = EvqBuffer;
1949
1950 switch (structBuffType) {
1951 case EHTokAppendStructuredBuffer:
1952 unimplemented("AppendStructuredBuffer");
1953 return false;
1954 case EHTokByteAddressBuffer:
1955 hasTemplateType = false;
1956 readonly = true;
1957 break;
1958 case EHTokConsumeStructuredBuffer:
1959 unimplemented("ConsumeStructuredBuffer");
1960 return false;
1961 case EHTokRWByteAddressBuffer:
1962 hasTemplateType = false;
1963 break;
1964 case EHTokRWStructuredBuffer:
1965 break;
1966 case EHTokStructuredBuffer:
1967 readonly = true;
1968 break;
1969 default:
1970 return false; // not a structure buffer type
1971 }
1972
1973 advanceToken(); // consume the structure keyword
1974
1975 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1976 TType* templateType = new TType;
1977
1978 if (hasTemplateType) {
1979 if (! acceptTokenClass(EHTokLeftAngle)) {
1980 expected("left angle bracket");
1981 return false;
1982 }
1983
1984 if (! acceptType(*templateType)) {
1985 expected("type");
1986 return false;
1987 }
1988 if (! acceptTokenClass(EHTokRightAngle)) {
1989 expected("right angle bracket");
1990 return false;
1991 }
1992 } else {
1993 // byte address buffers have no explicit type.
1994 TType uintType(EbtUint, storage);
1995 templateType->shallowCopy(uintType);
1996 }
1997
1998 // Create an unsized array out of that type.
1999 // TODO: does this work if it's already an array type?
2000 TArraySizes unsizedArray;
2001 unsizedArray.addInnerSize(UnsizedArraySize);
2002 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07002003 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07002004
2005 // field name is canonical for all structbuffers
2006 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07002007
2008 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07002009
steve-lunarg5da1f032017-02-12 17:50:28 -07002010 TTypeList* blockStruct = new TTypeList;
2011 TTypeLoc member = { templateType, token.loc };
2012 blockStruct->push_back(member);
2013
steve-lunargdd8287a2017-02-23 18:04:12 -07002014 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07002015 TType blockType(blockStruct, "", templateType->getQualifier());
2016
steve-lunargdd8287a2017-02-23 18:04:12 -07002017 blockType.getQualifier().storage = storage;
2018 blockType.getQualifier().readonly = readonly;
2019
2020 // We may have created an equivalent type before, in which case we should use its
2021 // deep structure.
2022 parseContext.shareStructBufferType(blockType);
2023
steve-lunarg5da1f032017-02-12 17:50:28 -07002024 type.shallowCopy(blockType);
2025
2026 return true;
2027}
2028
John Kesseniche6e74942016-06-11 16:43:14 -06002029// struct_declaration_list
2030// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
2031//
2032// struct_declaration
2033// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002034// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06002035//
2036// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06002037// : IDENTIFIER post_decls
2038// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07002039// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06002040//
John Kessenichaa3c64c2017-03-28 09:52:38 -06002041bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList,
John Kessenichf3d88bd2017-03-19 12:24:29 -06002042 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06002043{
2044 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002045 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06002046
2047 do {
2048 // success on seeing the RIGHT_BRACE coming up
2049 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07002050 break;
John Kesseniche6e74942016-06-11 16:43:14 -06002051
2052 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07002053
2054 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002055
2056 // fully_specified_type
2057 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07002058 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002059 expected("member type");
2060 return false;
2061 }
2062
2063 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07002064 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06002065 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002066 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002067 expected("member name");
2068 return false;
2069 }
2070
John Kessenich54ee28f2017-03-11 14:13:00 -07002071 if (peekTokenClass(EHTokLeftParen)) {
2072 // function_parameters
2073 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002074 declarators.resize(declarators.size() + 1);
2075 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002076 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2077 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002078 if (functionDefinitionAccepted)
2079 break;
2080 }
2081 expected("member-function definition");
2082 return false;
2083 } else {
2084 // add it to the list of members
2085 TTypeLoc member = { new TType(EbtVoid), token.loc };
2086 member.type->shallowCopy(memberType);
2087 member.type->setFieldName(*idToken.string);
2088 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002089
John Kessenich54ee28f2017-03-11 14:13:00 -07002090 // array_specifier
2091 TArraySizes* arraySizes = nullptr;
2092 acceptArraySpecifier(arraySizes);
2093 if (arraySizes)
2094 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002095
John Kessenich54ee28f2017-03-11 14:13:00 -07002096 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002097
John Kessenich54ee28f2017-03-11 14:13:00 -07002098 // EQUAL assignment_expression
2099 if (acceptTokenClass(EHTokAssign)) {
2100 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2101 TIntermTyped* expressionNode = nullptr;
2102 if (! acceptAssignmentExpression(expressionNode)) {
2103 expected("initializer");
2104 return false;
2105 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002106 }
2107 }
John Kesseniche6e74942016-06-11 16:43:14 -06002108 // success on seeing the SEMICOLON coming up
2109 if (peekTokenClass(EHTokSemicolon))
2110 break;
2111
2112 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002113 if (acceptTokenClass(EHTokComma))
2114 declarator_list = true;
2115 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002116 expected(",");
2117 return false;
2118 }
2119
2120 } while (true);
2121
2122 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002123 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002124 expected(";");
2125 return false;
2126 }
2127
2128 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002129
John Kessenichb16f7e62017-03-11 19:32:47 -07002130 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002131}
2132
John Kessenich54ee28f2017-03-11 14:13:00 -07002133// member_function_definition
2134// | function_parameters post_decls compound_statement
2135//
2136// Expects type to have EvqGlobal for a static member and
2137// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002138bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2139 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002140{
John Kessenich54ee28f2017-03-11 14:13:00 -07002141 bool accepted = false;
2142
John Kessenich4dc835c2017-03-28 23:43:10 -06002143 const TString* functionName = &memberName;
2144 parseContext.getFullNamespaceName(functionName);
John Kessenich088d52b2017-03-11 17:55:28 -07002145 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002146 if (type.getQualifier().storage == EvqTemporary)
2147 declarator.function->setImplicitThis();
John Kessenich37789792017-03-21 23:56:40 -06002148 else
2149 declarator.function->setIllegalImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002150
2151 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002152 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002153 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002154 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002155
2156 // compound_statement (function body definition)
2157 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002158 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002159 declarator.body = new TVector<HlslToken>;
2160 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002161 }
2162 } else
2163 expected("function parameter list");
2164
John Kessenich54ee28f2017-03-11 14:13:00 -07002165 return accepted;
2166}
2167
John Kessenich5f934b02016-03-13 17:58:25 -06002168// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002169// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002170// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002171//
2172bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2173{
John Kessenich078d7f22016-03-14 10:02:11 -06002174 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002175 if (! acceptTokenClass(EHTokLeftParen))
2176 return false;
2177
John Kessenich71351de2016-06-08 12:50:56 -06002178 // VOID RIGHT_PAREN
2179 if (! acceptTokenClass(EHTokVoid)) {
2180 do {
2181 // parameter_declaration
2182 if (! acceptParameterDeclaration(function))
2183 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002184
John Kessenich71351de2016-06-08 12:50:56 -06002185 // COMMA
2186 if (! acceptTokenClass(EHTokComma))
2187 break;
2188 } while (true);
2189 }
John Kessenich5f934b02016-03-13 17:58:25 -06002190
John Kessenich078d7f22016-03-14 10:02:11 -06002191 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002192 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002193 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002194 return false;
2195 }
2196
2197 return true;
2198}
2199
steve-lunarg26d31452016-12-23 18:56:57 -07002200// default_parameter_declaration
2201// : EQUAL conditional_expression
2202// : EQUAL initializer
2203bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2204{
2205 node = nullptr;
2206
2207 // Valid not to have a default_parameter_declaration
2208 if (!acceptTokenClass(EHTokAssign))
2209 return true;
2210
2211 if (!acceptConditionalExpression(node)) {
2212 if (!acceptInitializer(node))
2213 return false;
2214
2215 // For initializer lists, we have to const-fold into a constructor for the type, so build
2216 // that.
2217 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2218 if (constructor == nullptr) // cannot construct
2219 return false;
2220
2221 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002222 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002223 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002224
steve-lunarg26d31452016-12-23 18:56:57 -07002225 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2226 }
2227
2228 // If this is simply a constant, we can use it directly.
2229 if (node->getAsConstantUnion())
2230 return true;
2231
2232 // Otherwise, it has to be const-foldable.
2233 TIntermTyped* origNode = node;
2234
2235 node = intermediate.fold(node->getAsAggregate());
2236
2237 if (node != nullptr && origNode != node)
2238 return true;
2239
2240 parseContext.error(token.loc, "invalid default parameter value", "", "");
2241
2242 return false;
2243}
2244
John Kessenich5f934b02016-03-13 17:58:25 -06002245// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002246// : fully_specified_type post_decls [ = default_parameter_declaration ]
2247// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002248//
2249bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2250{
2251 // fully_specified_type
2252 TType* type = new TType;
2253 if (! acceptFullySpecifiedType(*type))
2254 return false;
2255
2256 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002257 HlslToken idToken;
2258 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002259
John Kessenich19b92ff2016-06-19 11:50:34 -06002260 // array_specifier
2261 TArraySizes* arraySizes = nullptr;
2262 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002263 if (arraySizes) {
2264 if (arraySizes->isImplicit()) {
2265 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2266 return false;
2267 }
2268
John Kessenich19b92ff2016-06-19 11:50:34 -06002269 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002270 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002271
2272 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002273 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002274
steve-lunarg26d31452016-12-23 18:56:57 -07002275 TIntermTyped* defaultValue;
2276 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2277 return false;
2278
John Kessenich5aa59e22016-06-17 15:50:47 -06002279 parseContext.paramFix(*type);
2280
steve-lunarg26d31452016-12-23 18:56:57 -07002281 // If any prior parameters have default values, all the parameters after that must as well.
2282 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2283 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2284 return false;
2285 }
2286
2287 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002288 function.addParameter(param);
2289
2290 return true;
2291}
2292
2293// Do the work to create the function definition in addition to
2294// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002295//
2296// If 'deferredTokens' are passed in, just get the token stream,
2297// don't process.
2298//
2299bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2300 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002301{
John Kessenich088d52b2017-03-11 17:55:28 -07002302 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002303
John Kessenichb16f7e62017-03-11 19:32:47 -07002304 if (deferredTokens)
2305 return captureBlockTokens(*deferredTokens);
2306 else
John Kessenich4960baa2017-03-19 18:09:59 -06002307 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002308}
2309
2310bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2311{
2312 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002313 TIntermNode* entryPointNode = nullptr;
2314
John Kessenich077e0522016-06-09 02:02:17 -06002315 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002316 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2317 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002318
2319 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002320 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002321 if (! acceptCompoundStatement(functionBody))
2322 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002323
John Kessenich54ee28f2017-03-11 14:13:00 -07002324 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002325 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002326
2327 // Hook up the 1 or 2 function definitions.
2328 nodeList = intermediate.growAggregate(nodeList, functionNode);
2329 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002330
2331 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002332}
2333
John Kessenich0d2b6de2016-06-05 11:23:11 -06002334// Accept an expression with parenthesis around it, where
2335// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002336// syntactically required ones like in "if ( expression )".
2337//
2338// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002339//
2340// Note this one is not set up to be speculative; as it gives
2341// errors if not found.
2342//
2343bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2344{
2345 // LEFT_PAREN
2346 if (! acceptTokenClass(EHTokLeftParen))
2347 expected("(");
2348
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002349 bool decl = false;
2350 TIntermNode* declNode = nullptr;
2351 decl = acceptControlDeclaration(declNode);
2352 if (decl) {
2353 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2354 expected("initialized declaration");
2355 return false;
2356 } else
2357 expression = declNode->getAsTyped();
2358 } else {
2359 // no declaration
2360 if (! acceptExpression(expression)) {
2361 expected("expression");
2362 return false;
2363 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002364 }
2365
2366 // RIGHT_PAREN
2367 if (! acceptTokenClass(EHTokRightParen))
2368 expected(")");
2369
2370 return true;
2371}
2372
John Kessenich34fb0362016-05-03 23:17:20 -06002373// The top-level full expression recognizer.
2374//
John Kessenich87142c72016-03-12 20:24:24 -07002375// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002376// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002377//
2378bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2379{
LoopDawgef764a22016-06-03 09:17:51 -06002380 node = nullptr;
2381
John Kessenich34fb0362016-05-03 23:17:20 -06002382 // assignment_expression
2383 if (! acceptAssignmentExpression(node))
2384 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002385
John Kessenich34fb0362016-05-03 23:17:20 -06002386 if (! peekTokenClass(EHTokComma))
2387 return true;
2388
2389 do {
2390 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002391 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002392 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002393
John Kessenich34fb0362016-05-03 23:17:20 -06002394 // ... assignment_expression
2395 TIntermTyped* rightNode = nullptr;
2396 if (! acceptAssignmentExpression(rightNode)) {
2397 expected("assignment expression");
2398 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002399 }
2400
John Kessenich34fb0362016-05-03 23:17:20 -06002401 node = intermediate.addComma(node, rightNode, loc);
2402
2403 if (! peekTokenClass(EHTokComma))
2404 return true;
2405 } while (true);
2406}
2407
John Kessenich07354242016-07-01 19:58:06 -06002408// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002409// : LEFT_BRACE RIGHT_BRACE
2410// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002411//
2412// initializer_list
2413// : assignment_expression COMMA assignment_expression COMMA ...
2414//
2415bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2416{
2417 // LEFT_BRACE
2418 if (! acceptTokenClass(EHTokLeftBrace))
2419 return false;
2420
John Kessenich98ad4852016-11-27 17:39:07 -07002421 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002422 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002423 if (acceptTokenClass(EHTokRightBrace)) {
2424 // a zero-length initializer list
2425 node = intermediate.makeAggregate(loc);
2426 return true;
2427 }
2428
2429 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002430 node = nullptr;
2431 do {
2432 // assignment_expression
2433 TIntermTyped* expr;
2434 if (! acceptAssignmentExpression(expr)) {
2435 expected("assignment expression in initializer list");
2436 return false;
2437 }
2438 node = intermediate.growAggregate(node, expr, loc);
2439
2440 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002441 if (acceptTokenClass(EHTokComma)) {
2442 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2443 return true;
John Kessenich07354242016-07-01 19:58:06 -06002444 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002445 }
John Kessenich07354242016-07-01 19:58:06 -06002446
2447 // RIGHT_BRACE
2448 if (acceptTokenClass(EHTokRightBrace))
2449 return true;
2450
2451 expected(", or }");
2452 return false;
2453 } while (true);
2454}
2455
John Kessenich34fb0362016-05-03 23:17:20 -06002456// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002457// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002458//
2459// a op (b op (c op d))
2460//
2461// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002462// : initializer
2463// | conditional_expression
2464// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002465//
2466bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2467{
John Kessenich07354242016-07-01 19:58:06 -06002468 // initializer
2469 if (peekTokenClass(EHTokLeftBrace)) {
2470 if (acceptInitializer(node))
2471 return true;
2472
2473 expected("initializer");
2474 return false;
2475 }
2476
John Kessenich00957f82016-07-27 10:39:57 -06002477 // conditional_expression
2478 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002479 return false;
2480
John Kessenich07354242016-07-01 19:58:06 -06002481 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002482 TOperator assignOp = HlslOpMap::assignment(peek());
2483 if (assignOp == EOpNull)
2484 return true;
2485
John Kessenich00957f82016-07-27 10:39:57 -06002486 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002487 TSourceLoc loc = token.loc;
2488 advanceToken();
2489
John Kessenich00957f82016-07-27 10:39:57 -06002490 // conditional_expression assign_op conditional_expression ...
2491 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002492 // gets the right-to-left associativity.
2493 TIntermTyped* rightNode = nullptr;
2494 if (! acceptAssignmentExpression(rightNode)) {
2495 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002496 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002497 }
2498
John Kessenichd21baed2016-09-16 03:05:12 -06002499 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002500 node = parseContext.handleLvalue(loc, "assign", node);
2501
John Kessenichfea226b2016-07-28 17:53:56 -06002502 if (node == nullptr) {
2503 parseContext.error(loc, "could not create assignment", "", "");
2504 return false;
2505 }
John Kessenich34fb0362016-05-03 23:17:20 -06002506
2507 if (! peekTokenClass(EHTokComma))
2508 return true;
2509
2510 return true;
2511}
2512
John Kessenich00957f82016-07-27 10:39:57 -06002513// Accept a conditional expression, which associates right-to-left,
2514// accomplished by the "true" expression calling down to lower
2515// precedence levels than this level.
2516//
2517// conditional_expression
2518// : binary_expression
2519// | binary_expression QUESTION expression COLON assignment_expression
2520//
2521bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2522{
2523 // binary_expression
2524 if (! acceptBinaryExpression(node, PlLogicalOr))
2525 return false;
2526
2527 if (! acceptTokenClass(EHTokQuestion))
2528 return true;
2529
John Kessenich7e997e22017-03-30 22:09:30 -06002530 node = parseContext.convertConditionalExpression(token.loc, node);
2531 if (node == nullptr)
2532 return false;
2533
John Kessenich00957f82016-07-27 10:39:57 -06002534 TIntermTyped* trueNode = nullptr;
2535 if (! acceptExpression(trueNode)) {
2536 expected("expression after ?");
2537 return false;
2538 }
2539 TSourceLoc loc = token.loc;
2540
2541 if (! acceptTokenClass(EHTokColon)) {
2542 expected(":");
2543 return false;
2544 }
2545
2546 TIntermTyped* falseNode = nullptr;
2547 if (! acceptAssignmentExpression(falseNode)) {
2548 expected("expression after :");
2549 return false;
2550 }
2551
2552 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2553
2554 return true;
2555}
2556
John Kessenich34fb0362016-05-03 23:17:20 -06002557// Accept a binary expression, for binary operations that
2558// associate left-to-right. This is, it is implicit, for example
2559//
2560// ((a op b) op c) op d
2561//
2562// binary_expression
2563// : expression op expression op expression ...
2564//
2565// where 'expression' is the next higher level in precedence.
2566//
2567bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2568{
2569 if (precedenceLevel > PlMul)
2570 return acceptUnaryExpression(node);
2571
2572 // assignment_expression
2573 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2574 return false;
2575
John Kessenich34fb0362016-05-03 23:17:20 -06002576 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002577 TOperator op = HlslOpMap::binary(peek());
2578 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2579 if (tokenLevel < precedenceLevel)
2580 return true;
2581
John Kessenich34fb0362016-05-03 23:17:20 -06002582 // ... op
2583 TSourceLoc loc = token.loc;
2584 advanceToken();
2585
2586 // ... expression
2587 TIntermTyped* rightNode = nullptr;
2588 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2589 expected("expression");
2590 return false;
2591 }
2592
2593 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002594 if (node == nullptr) {
2595 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2596 return false;
2597 }
John Kessenich34fb0362016-05-03 23:17:20 -06002598 } while (true);
2599}
2600
2601// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002602// : (type) unary_expression
2603// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002604// | - unary_expression
2605// | ! unary_expression
2606// | ~ unary_expression
2607// | ++ unary_expression
2608// | -- unary_expression
2609// | postfix_expression
2610//
2611bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2612{
John Kessenich1cc1a282016-06-03 16:55:49 -06002613 // (type) unary_expression
2614 // Have to look two steps ahead, because this could be, e.g., a
2615 // postfix_expression instead, since that also starts with at "(".
2616 if (acceptTokenClass(EHTokLeftParen)) {
2617 TType castType;
2618 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002619 if (acceptTokenClass(EHTokRightParen)) {
2620 // We've matched "(type)" now, get the expression to cast
2621 TSourceLoc loc = token.loc;
2622 if (! acceptUnaryExpression(node))
2623 return false;
2624
2625 // Hook it up like a constructor
2626 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2627 if (constructorFunction == nullptr) {
2628 expected("type that can be constructed");
2629 return false;
2630 }
2631 TIntermTyped* arguments = nullptr;
2632 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2633 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2634
2635 return true;
2636 } else {
2637 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2638 // the '(int' part. We must back up twice.
2639 recedeToken();
2640 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002641 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002642 } else {
2643 // This isn't a type cast, but it still started "(", so if it is a
2644 // unary expression, it can only be a postfix_expression, so try that.
2645 // Back it up first.
2646 recedeToken();
2647 return acceptPostfixExpression(node);
2648 }
2649 }
2650
2651 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002652 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002653
John Kessenich1cc1a282016-06-03 16:55:49 -06002654 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002655 if (unaryOp == EOpNull)
2656 return acceptPostfixExpression(node);
2657
2658 // op unary_expression
2659 TSourceLoc loc = token.loc;
2660 advanceToken();
2661 if (! acceptUnaryExpression(node))
2662 return false;
2663
2664 // + is a no-op
2665 if (unaryOp == EOpAdd)
2666 return true;
2667
2668 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002669
2670 // These unary ops require lvalues
2671 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2672 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002673
2674 return node != nullptr;
2675}
2676
2677// postfix_expression
2678// : LEFT_PAREN expression RIGHT_PAREN
2679// | literal
2680// | constructor
John Kessenich8f9fdc92017-03-30 16:22:26 -06002681// | IDENTIFIER [ COLONCOLON IDENTIFIER [ COLONCOLON IDENTIFIER ... ] ]
John Kessenich34fb0362016-05-03 23:17:20 -06002682// | function_call
2683// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2684// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002685// | postfix_expression DOT IDENTIFIER arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002686// | postfix_expression arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002687// | postfix_expression INC_OP
2688// | postfix_expression DEC_OP
2689//
2690bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2691{
2692 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002693 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002694
2695 // idToken will pick up either a variable or a function name in a function call
2696 HlslToken idToken;
2697
John Kessenich21472ae2016-06-04 11:46:33 -06002698 // Find something before the postfix operations, as they can't operate
2699 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002700 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002701 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002702 if (! acceptExpression(node)) {
2703 expected("expression");
2704 return false;
2705 }
2706 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002707 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002708 return false;
2709 }
John Kessenich34fb0362016-05-03 23:17:20 -06002710 } else if (acceptLiteral(node)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002711 // literal (nothing else to do yet)
John Kessenich34fb0362016-05-03 23:17:20 -06002712 } else if (acceptConstructor(node)) {
2713 // constructor (nothing else to do yet)
2714 } else if (acceptIdentifier(idToken)) {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002715 // user-type, namespace name, variable, or function name
2716 TString* fullName = idToken.string;
2717 while (acceptTokenClass(EHTokColonColon)) {
2718 // user-type or namespace name
2719 fullName = NewPoolTString(fullName->c_str());
2720 fullName->append(parseContext.scopeMangler);
2721 if (acceptIdentifier(idToken))
2722 fullName->append(*idToken.string);
2723 else {
2724 expected("identifier after ::");
John Kessenich54ee28f2017-03-11 14:13:00 -07002725 return false;
2726 }
John Kessenich8f9fdc92017-03-30 16:22:26 -06002727 }
2728 if (! peekTokenClass(EHTokLeftParen)) {
2729 node = parseContext.handleVariable(idToken.loc, fullName);
2730 } else if (acceptFunctionCall(idToken.loc, *fullName, node, nullptr)) {
John Kessenich34fb0362016-05-03 23:17:20 -06002731 // function_call (nothing else to do yet)
2732 } else {
2733 expected("function call arguments");
2734 return false;
2735 }
John Kessenich21472ae2016-06-04 11:46:33 -06002736 } else {
2737 // nothing found, can't post operate
2738 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002739 }
2740
steve-lunarga2b01a02016-11-28 17:09:54 -07002741 // This is to guarantee we do this no matter how we get out of the stack frame.
2742 // This way there's no bug if an early return forgets to do it.
2743 struct tFinalize {
2744 tFinalize(HlslParseContext& p) : parseContext(p) { }
2745 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002746 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002747 private:
John Kessenichca71d942017-03-07 20:44:09 -07002748 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002749 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002750 } finalize(parseContext);
2751
2752 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2753 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2754 // level: hence the init and finalize. Even though in practice these must be
2755 // constants, they are parsed no matter what.
2756 parseContext.initFlattening();
2757
John Kessenich21472ae2016-06-04 11:46:33 -06002758 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002759 do {
2760 TSourceLoc loc = token.loc;
2761 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002762
John Kessenich34fb0362016-05-03 23:17:20 -06002763 // Consume only a valid post-unary operator, otherwise we are done.
2764 switch (postOp) {
2765 case EOpIndexDirectStruct:
2766 case EOpIndexIndirect:
2767 case EOpPostIncrement:
2768 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002769 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002770 advanceToken();
2771 break;
2772 default:
2773 return true;
2774 }
John Kessenich87142c72016-03-12 20:24:24 -07002775
John Kessenich34fb0362016-05-03 23:17:20 -06002776 // We have a valid post-unary operator, process it.
2777 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002778 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002779 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002780 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002781 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002782 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002783 HlslToken field;
2784 if (! acceptIdentifier(field)) {
2785 expected("swizzle or member");
2786 return false;
2787 }
LoopDawg4886f692016-06-29 10:58:58 -06002788
John Kessenich516d92d2017-03-08 20:09:03 -07002789 if (peekTokenClass(EHTokLeftParen)) {
2790 // member function
2791 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002792
John Kessenich516d92d2017-03-08 20:09:03 -07002793 // arguments
John Kessenich8f9fdc92017-03-30 16:22:26 -06002794 if (! acceptFunctionCall(field.loc, *field.string, node, thisNode)) {
LoopDawg4886f692016-06-29 10:58:58 -06002795 expected("function parameters");
2796 return false;
2797 }
John Kessenich516d92d2017-03-08 20:09:03 -07002798 } else
2799 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002800
John Kessenich34fb0362016-05-03 23:17:20 -06002801 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002802 }
John Kessenich34fb0362016-05-03 23:17:20 -06002803 case EOpIndexIndirect:
2804 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002805 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002806 TIntermTyped* indexNode = nullptr;
2807 if (! acceptExpression(indexNode) ||
2808 ! peekTokenClass(EHTokRightBracket)) {
2809 expected("expression followed by ']'");
2810 return false;
2811 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002812 advanceToken();
2813 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2814 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002815 }
2816 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002817 // INC_OP
2818 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002819 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002820 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002821 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002822 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002823 break;
2824 default:
2825 assert(0);
2826 break;
2827 }
2828 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002829}
2830
John Kessenichd016be12016-03-13 11:24:20 -06002831// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002832// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002833//
2834bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2835{
2836 // type
2837 TType type;
2838 if (acceptType(type)) {
2839 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2840 if (constructorFunction == nullptr)
2841 return false;
2842
2843 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002844 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002845 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002846 // It's possible this is a type keyword used as an identifier. Put the token back
2847 // for later use.
2848 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002849 return false;
2850 }
2851
2852 // hook it up
2853 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2854
2855 return true;
2856 }
2857
2858 return false;
2859}
2860
John Kessenich34fb0362016-05-03 23:17:20 -06002861// The function_call identifier was already recognized, and passed in as idToken.
2862//
2863// function_call
2864// : [idToken] arguments
2865//
John Kessenich8f9fdc92017-03-30 16:22:26 -06002866bool HlslGrammar::acceptFunctionCall(const TSourceLoc& loc, TString& name, TIntermTyped*& node, TIntermTyped* baseObject)
John Kessenich34fb0362016-05-03 23:17:20 -06002867{
John Kessenich54ee28f2017-03-11 14:13:00 -07002868 // name
2869 TString* functionName = nullptr;
John Kessenich8f9fdc92017-03-30 16:22:26 -06002870 if (baseObject == nullptr) {
2871 functionName = &name;
2872 } else if (parseContext.isBuiltInMethod(loc, baseObject, name)) {
John Kessenich4960baa2017-03-19 18:09:59 -06002873 // Built-in methods are not in the symbol table as methods, but as global functions
2874 // taking an explicit 'this' as the first argument.
steve-lunarge7d07522017-03-19 18:12:37 -06002875 functionName = NewPoolTString(BUILTIN_PREFIX);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002876 functionName->append(name);
John Kessenich4960baa2017-03-19 18:09:59 -06002877 } else {
John Kessenich8f9fdc92017-03-30 16:22:26 -06002878 if (! baseObject->getType().isStruct()) {
2879 expected("structure");
2880 return false;
2881 }
John Kessenich54ee28f2017-03-11 14:13:00 -07002882 functionName = NewPoolTString("");
John Kessenich8f9fdc92017-03-30 16:22:26 -06002883 functionName->append(baseObject->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002884 parseContext.addScopeMangler(*functionName);
John Kessenich8f9fdc92017-03-30 16:22:26 -06002885 functionName->append(name);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002886 }
LoopDawg4886f692016-06-29 10:58:58 -06002887
John Kessenich54ee28f2017-03-11 14:13:00 -07002888 // function
2889 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2890
2891 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002892 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002893 if (baseObject != nullptr) {
2894 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002895 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002896 }
John Kessenich4678ca92016-05-13 09:33:42 -06002897 if (! acceptArguments(function, arguments))
2898 return false;
2899
John Kessenich54ee28f2017-03-11 14:13:00 -07002900 // call
John Kessenich8f9fdc92017-03-30 16:22:26 -06002901 node = parseContext.handleFunctionCall(loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002902
2903 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002904}
2905
John Kessenich87142c72016-03-12 20:24:24 -07002906// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002907// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002908//
John Kessenichd016be12016-03-13 11:24:20 -06002909// The arguments are pushed onto the 'function' argument list and
2910// onto the 'arguments' aggregate.
2911//
John Kessenich4678ca92016-05-13 09:33:42 -06002912bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002913{
John Kessenich078d7f22016-03-14 10:02:11 -06002914 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002915 if (! acceptTokenClass(EHTokLeftParen))
2916 return false;
2917
2918 do {
John Kessenichd016be12016-03-13 11:24:20 -06002919 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002920 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002921 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002922 break;
John Kessenichd016be12016-03-13 11:24:20 -06002923
2924 // hook it up
2925 parseContext.handleFunctionArgument(function, arguments, arg);
2926
John Kessenich078d7f22016-03-14 10:02:11 -06002927 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002928 if (! acceptTokenClass(EHTokComma))
2929 break;
2930 } while (true);
2931
John Kessenich078d7f22016-03-14 10:02:11 -06002932 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002933 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002934 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002935 return false;
2936 }
2937
2938 return true;
2939}
2940
2941bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2942{
2943 switch (token.tokenClass) {
2944 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002945 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002946 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002947 case EHTokUintConstant:
2948 node = intermediate.addConstantUnion(token.u, token.loc, true);
2949 break;
John Kessenich87142c72016-03-12 20:24:24 -07002950 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002951 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002952 break;
2953 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002954 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002955 break;
2956 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002957 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002958 break;
John Kessenich86f71382016-09-19 20:23:18 -06002959 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002960 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002961 break;
John Kessenich87142c72016-03-12 20:24:24 -07002962
2963 default:
2964 return false;
2965 }
2966
2967 advanceToken();
2968
2969 return true;
2970}
2971
John Kessenich5f934b02016-03-13 17:58:25 -06002972// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002973// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002974//
John Kessenich21472ae2016-06-04 11:46:33 -06002975bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002976{
John Kessenich21472ae2016-06-04 11:46:33 -06002977 TIntermAggregate* compoundStatement = nullptr;
2978
John Kessenich34fb0362016-05-03 23:17:20 -06002979 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002980 if (! acceptTokenClass(EHTokLeftBrace))
2981 return false;
2982
2983 // statement statement ...
2984 TIntermNode* statement = nullptr;
2985 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002986 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2987 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2988 branch->getFlowOp() == EOpDefault)) {
2989 // hook up individual subsequences within a switch statement
2990 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2991 compoundStatement = nullptr;
2992 } else {
2993 // hook it up to the growing compound statement
2994 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2995 }
John Kessenich5f934b02016-03-13 17:58:25 -06002996 }
John Kessenich34fb0362016-05-03 23:17:20 -06002997 if (compoundStatement)
2998 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002999
John Kessenich21472ae2016-06-04 11:46:33 -06003000 retStatement = compoundStatement;
3001
John Kessenich34fb0362016-05-03 23:17:20 -06003002 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06003003 return acceptTokenClass(EHTokRightBrace);
3004}
3005
John Kessenich0d2b6de2016-06-05 11:23:11 -06003006bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
3007{
3008 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06003009 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003010 parseContext.popScope();
3011
3012 return result;
3013}
3014
John Kessenich077e0522016-06-09 02:02:17 -06003015bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003016{
John Kessenich077e0522016-06-09 02:02:17 -06003017 parseContext.pushScope();
3018 bool result = acceptCompoundStatement(statement);
3019 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06003020
3021 return result;
3022}
3023
John Kessenich5f934b02016-03-13 17:58:25 -06003024// statement
John Kessenich21472ae2016-06-04 11:46:33 -06003025// : attributes attributed_statement
3026//
3027// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003028// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06003029// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06003030// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06003031// | declaration_statement
3032// | selection_statement
3033// | switch_statement
3034// | case_label
3035// | iteration_statement
3036// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06003037//
3038bool HlslGrammar::acceptStatement(TIntermNode*& statement)
3039{
John Kessenich21472ae2016-06-04 11:46:33 -06003040 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06003041
John Kessenich21472ae2016-06-04 11:46:33 -06003042 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06003043 TAttributeMap attributes;
3044 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06003045
John Kessenich21472ae2016-06-04 11:46:33 -06003046 // attributed_statement
3047 switch (peek()) {
3048 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06003049 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003050
John Kessenich21472ae2016-06-04 11:46:33 -06003051 case EHTokIf:
3052 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003053
John Kessenich21472ae2016-06-04 11:46:33 -06003054 case EHTokSwitch:
3055 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06003056
John Kessenich21472ae2016-06-04 11:46:33 -06003057 case EHTokFor:
3058 case EHTokDo:
3059 case EHTokWhile:
3060 return acceptIterationStatement(statement);
3061
3062 case EHTokContinue:
3063 case EHTokBreak:
3064 case EHTokDiscard:
3065 case EHTokReturn:
3066 return acceptJumpStatement(statement);
3067
3068 case EHTokCase:
3069 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06003070 case EHTokDefault:
3071 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06003072
3073 case EHTokSemicolon:
3074 return acceptTokenClass(EHTokSemicolon);
3075
3076 case EHTokRightBrace:
3077 // Performance: not strictly necessary, but stops a bunch of hunting early,
3078 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06003079 return false;
3080
John Kessenich21472ae2016-06-04 11:46:33 -06003081 default:
3082 {
3083 // declaration
3084 if (acceptDeclaration(statement))
3085 return true;
3086
3087 // expression
3088 TIntermTyped* node;
3089 if (acceptExpression(node))
3090 statement = node;
3091 else
3092 return false;
3093
3094 // SEMICOLON (following an expression)
3095 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003096 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003097 return false;
3098 }
3099 }
3100 }
3101
John Kessenich5f934b02016-03-13 17:58:25 -06003102 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003103}
3104
John Kessenich21472ae2016-06-04 11:46:33 -06003105// attributes
3106// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3107//
3108// attribute:
3109// : UNROLL
3110// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3111// | FASTOPT
3112// | ALLOW_UAV_CONDITION
3113// | BRANCH
3114// | FLATTEN
3115// | FORCECASE
3116// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003117// | DOMAIN
3118// | EARLYDEPTHSTENCIL
3119// | INSTANCE
3120// | MAXTESSFACTOR
3121// | OUTPUTCONTROLPOINTS
3122// | OUTPUTTOPOLOGY
3123// | PARTITIONING
3124// | PATCHCONSTANTFUNC
3125// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003126//
steve-lunarg1868b142016-10-20 13:07:10 -06003127void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003128{
steve-lunarg1868b142016-10-20 13:07:10 -06003129 // For now, accept the [ XXX(X) ] syntax, but drop all but
3130 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003131 // TODO: subset to correct set? Pass on?
3132 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003133 HlslToken idToken;
3134
John Kessenich0d2b6de2016-06-05 11:23:11 -06003135 // LEFT_BRACKET?
3136 if (! acceptTokenClass(EHTokLeftBracket))
3137 return;
3138
3139 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003140 if (acceptIdentifier(idToken)) {
3141 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003142 } else if (! peekTokenClass(EHTokRightBracket)) {
3143 expected("identifier");
3144 advanceToken();
3145 }
3146
steve-lunarga22f7db2016-11-11 08:17:44 -07003147 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003148
3149 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003150 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003151 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003152
John Kessenich0d2b6de2016-06-05 11:23:11 -06003153 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003154 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003155
steve-lunarga22f7db2016-11-11 08:17:44 -07003156 while (acceptAssignmentExpression(node)) {
3157 expectingExpression = false;
3158 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003159 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003160 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003161 }
3162
steve-lunarga22f7db2016-11-11 08:17:44 -07003163 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003164 if (! acceptTokenClass(EHTokRightParen))
3165 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003166
3167 // Error for partial or missing expression
3168 if (expectingExpression || expressions->getSequence().empty())
3169 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003170 }
3171
3172 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003173 if (!acceptTokenClass(EHTokRightBracket)) {
3174 expected("]");
3175 return;
3176 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003177
steve-lunarg1868b142016-10-20 13:07:10 -06003178 // Add any values we found into the attribute map. This accepts
3179 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003180 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003181 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003182}
3183
John Kessenich0d2b6de2016-06-05 11:23:11 -06003184// selection_statement
3185// : IF LEFT_PAREN expression RIGHT_PAREN statement
3186// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3187//
John Kessenich21472ae2016-06-04 11:46:33 -06003188bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3189{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003190 TSourceLoc loc = token.loc;
3191
3192 // IF
3193 if (! acceptTokenClass(EHTokIf))
3194 return false;
3195
3196 // so that something declared in the condition is scoped to the lifetimes
3197 // of the then-else statements
3198 parseContext.pushScope();
3199
3200 // LEFT_PAREN expression RIGHT_PAREN
3201 TIntermTyped* condition;
3202 if (! acceptParenExpression(condition))
3203 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003204 condition = parseContext.convertConditionalExpression(loc, condition);
3205 if (condition == nullptr)
3206 return false;
John Kessenich0d2b6de2016-06-05 11:23:11 -06003207
3208 // create the child statements
3209 TIntermNodePair thenElse = { nullptr, nullptr };
3210
3211 // then statement
3212 if (! acceptScopedStatement(thenElse.node1)) {
3213 expected("then statement");
3214 return false;
3215 }
3216
3217 // ELSE
3218 if (acceptTokenClass(EHTokElse)) {
3219 // else statement
3220 if (! acceptScopedStatement(thenElse.node2)) {
3221 expected("else statement");
3222 return false;
3223 }
3224 }
3225
3226 // Put the pieces together
3227 statement = intermediate.addSelection(condition, thenElse, loc);
3228 parseContext.popScope();
3229
3230 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003231}
3232
John Kessenichd02dc5d2016-07-01 00:04:11 -06003233// switch_statement
3234// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3235//
John Kessenich21472ae2016-06-04 11:46:33 -06003236bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3237{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003238 // SWITCH
3239 TSourceLoc loc = token.loc;
3240 if (! acceptTokenClass(EHTokSwitch))
3241 return false;
3242
3243 // LEFT_PAREN expression RIGHT_PAREN
3244 parseContext.pushScope();
3245 TIntermTyped* switchExpression;
3246 if (! acceptParenExpression(switchExpression)) {
3247 parseContext.popScope();
3248 return false;
3249 }
3250
3251 // compound_statement
3252 parseContext.pushSwitchSequence(new TIntermSequence);
3253 bool statementOkay = acceptCompoundStatement(statement);
3254 if (statementOkay)
3255 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3256
3257 parseContext.popSwitchSequence();
3258 parseContext.popScope();
3259
3260 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003261}
3262
John Kessenich119f8f62016-06-05 15:44:07 -06003263// iteration_statement
3264// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3265// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3266// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3267//
3268// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003269bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3270{
John Kessenich119f8f62016-06-05 15:44:07 -06003271 TSourceLoc loc = token.loc;
3272 TIntermTyped* condition = nullptr;
3273
3274 EHlslTokenClass loop = peek();
3275 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3276
3277 // WHILE or DO or FOR
3278 advanceToken();
3279
3280 switch (loop) {
3281 case EHTokWhile:
3282 // so that something declared in the condition is scoped to the lifetime
3283 // of the while sub-statement
3284 parseContext.pushScope();
3285 parseContext.nestLooping();
3286
3287 // LEFT_PAREN condition RIGHT_PAREN
3288 if (! acceptParenExpression(condition))
3289 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003290 condition = parseContext.convertConditionalExpression(loc, condition);
3291 if (condition == nullptr)
3292 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003293
3294 // statement
3295 if (! acceptScopedStatement(statement)) {
3296 expected("while sub-statement");
3297 return false;
3298 }
3299
3300 parseContext.unnestLooping();
3301 parseContext.popScope();
3302
3303 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3304
3305 return true;
3306
3307 case EHTokDo:
3308 parseContext.nestLooping();
3309
3310 if (! acceptTokenClass(EHTokLeftBrace))
3311 expected("{");
3312
3313 // statement
3314 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3315 expected("do sub-statement");
3316 return false;
3317 }
3318
3319 if (! acceptTokenClass(EHTokRightBrace))
3320 expected("}");
3321
3322 // WHILE
3323 if (! acceptTokenClass(EHTokWhile)) {
3324 expected("while");
3325 return false;
3326 }
3327
3328 // LEFT_PAREN condition RIGHT_PAREN
3329 TIntermTyped* condition;
3330 if (! acceptParenExpression(condition))
3331 return false;
John Kessenich7e997e22017-03-30 22:09:30 -06003332 condition = parseContext.convertConditionalExpression(loc, condition);
3333 if (condition == nullptr)
3334 return false;
John Kessenich119f8f62016-06-05 15:44:07 -06003335
3336 if (! acceptTokenClass(EHTokSemicolon))
3337 expected(";");
3338
3339 parseContext.unnestLooping();
3340
3341 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3342
3343 return true;
3344
3345 case EHTokFor:
3346 {
3347 // LEFT_PAREN
3348 if (! acceptTokenClass(EHTokLeftParen))
3349 expected("(");
3350
3351 // so that something declared in the condition is scoped to the lifetime
3352 // of the for sub-statement
3353 parseContext.pushScope();
3354
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003355 // initializer
3356 TIntermNode* initNode = nullptr;
3357 if (! acceptControlDeclaration(initNode)) {
3358 TIntermTyped* initExpr = nullptr;
3359 acceptExpression(initExpr);
3360 initNode = initExpr;
3361 }
3362 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003363 if (! acceptTokenClass(EHTokSemicolon))
3364 expected(";");
3365
3366 parseContext.nestLooping();
3367
3368 // condition SEMI_COLON
3369 acceptExpression(condition);
3370 if (! acceptTokenClass(EHTokSemicolon))
3371 expected(";");
John Kessenich7e997e22017-03-30 22:09:30 -06003372 if (condition != nullptr) {
3373 condition = parseContext.convertConditionalExpression(loc, condition);
3374 if (condition == nullptr)
3375 return false;
3376 }
John Kessenich119f8f62016-06-05 15:44:07 -06003377
3378 // iterator SEMI_COLON
3379 TIntermTyped* iterator = nullptr;
3380 acceptExpression(iterator);
3381 if (! acceptTokenClass(EHTokRightParen))
3382 expected(")");
3383
3384 // statement
3385 if (! acceptScopedStatement(statement)) {
3386 expected("for sub-statement");
3387 return false;
3388 }
3389
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003390 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003391
3392 parseContext.popScope();
3393 parseContext.unnestLooping();
3394
3395 return true;
3396 }
3397
3398 default:
3399 return false;
3400 }
John Kessenich21472ae2016-06-04 11:46:33 -06003401}
3402
3403// jump_statement
3404// : CONTINUE SEMICOLON
3405// | BREAK SEMICOLON
3406// | DISCARD SEMICOLON
3407// | RETURN SEMICOLON
3408// | RETURN expression SEMICOLON
3409//
3410bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3411{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003412 EHlslTokenClass jump = peek();
3413 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003414 case EHTokContinue:
3415 case EHTokBreak:
3416 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003417 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003418 advanceToken();
3419 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003420 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003421 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003422 return false;
3423 }
John Kessenich21472ae2016-06-04 11:46:33 -06003424
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003425 switch (jump) {
3426 case EHTokContinue:
3427 statement = intermediate.addBranch(EOpContinue, token.loc);
3428 break;
3429 case EHTokBreak:
3430 statement = intermediate.addBranch(EOpBreak, token.loc);
3431 break;
3432 case EHTokDiscard:
3433 statement = intermediate.addBranch(EOpKill, token.loc);
3434 break;
3435
3436 case EHTokReturn:
3437 {
3438 // expression
3439 TIntermTyped* node;
3440 if (acceptExpression(node)) {
3441 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003442 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003443 } else
3444 statement = intermediate.addBranch(EOpReturn, token.loc);
3445 break;
3446 }
3447
3448 default:
3449 assert(0);
3450 return false;
3451 }
3452
3453 // SEMICOLON
3454 if (! acceptTokenClass(EHTokSemicolon))
3455 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003456
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003457 return true;
3458}
John Kessenich21472ae2016-06-04 11:46:33 -06003459
John Kessenichd02dc5d2016-07-01 00:04:11 -06003460// case_label
3461// : CASE expression COLON
3462//
John Kessenich21472ae2016-06-04 11:46:33 -06003463bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3464{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003465 TSourceLoc loc = token.loc;
3466 if (! acceptTokenClass(EHTokCase))
3467 return false;
3468
3469 TIntermTyped* expression;
3470 if (! acceptExpression(expression)) {
3471 expected("case expression");
3472 return false;
3473 }
3474
3475 if (! acceptTokenClass(EHTokColon)) {
3476 expected(":");
3477 return false;
3478 }
3479
3480 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3481
3482 return true;
3483}
3484
3485// default_label
3486// : DEFAULT COLON
3487//
3488bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3489{
3490 TSourceLoc loc = token.loc;
3491 if (! acceptTokenClass(EHTokDefault))
3492 return false;
3493
3494 if (! acceptTokenClass(EHTokColon)) {
3495 expected(":");
3496 return false;
3497 }
3498
3499 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3500
3501 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003502}
3503
John Kessenich19b92ff2016-06-19 11:50:34 -06003504// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003505// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3506// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003507//
3508void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3509{
3510 arraySizes = nullptr;
3511
steve-lunarg7b211a32016-10-13 12:26:18 -06003512 // Early-out if there aren't any array dimensions
3513 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003514 return;
3515
steve-lunarg7b211a32016-10-13 12:26:18 -06003516 // 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 -06003517 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003518
3519 // Collect each array dimension.
3520 while (acceptTokenClass(EHTokLeftBracket)) {
3521 TSourceLoc loc = token.loc;
3522 TIntermTyped* sizeExpr = nullptr;
3523
John Kessenich057df292017-03-06 18:18:37 -07003524 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003525 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3526
3527 if (! acceptTokenClass(EHTokRightBracket)) {
3528 expected("]");
3529 return;
3530 }
3531
3532 if (hasArraySize) {
3533 TArraySize arraySize;
3534 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3535 arraySizes->addInnerSize(arraySize);
3536 } else {
3537 arraySizes->addInnerSize(0); // sized by initializers.
3538 }
steve-lunarg265c0612016-09-27 10:57:35 -06003539 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003540}
3541
John Kessenich630dd7d2016-06-12 23:52:12 -06003542// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003543// : COLON semantic // optional
3544// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3545// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003546// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003547// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003548//
John Kessenich854fe242017-03-02 14:30:59 -07003549// Return true if any tokens were accepted. That is,
3550// false can be returned on successfully recognizing nothing,
3551// not necessarily meaning bad syntax.
3552//
3553bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003554{
John Kessenich854fe242017-03-02 14:30:59 -07003555 bool found = false;
3556
John Kessenich630dd7d2016-06-12 23:52:12 -06003557 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003558 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003559 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003560 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003561 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003562 if (peekTokenClass(EHTokLayout))
3563 acceptLayoutQualifierList(qualifier);
3564 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003565 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003566 if (! acceptTokenClass(EHTokLeftParen)) {
3567 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003568 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003569 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003570 HlslToken locationToken;
3571 if (! acceptIdentifier(locationToken)) {
3572 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003573 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003574 }
3575 HlslToken componentToken;
3576 if (acceptTokenClass(EHTokDot)) {
3577 if (! acceptIdentifier(componentToken)) {
3578 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003579 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003580 }
3581 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003582 if (! acceptTokenClass(EHTokRightParen)) {
3583 expected(")");
3584 break;
3585 }
John Kessenich7735b942016-09-05 12:40:06 -06003586 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003587 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003588 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003589 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003590 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003591 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3592 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003593 if (! acceptTokenClass(EHTokLeftParen)) {
3594 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003595 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003596 }
John Kessenichb38f0712016-07-30 10:29:54 -06003597 HlslToken registerDesc; // for Type#
3598 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003599 if (! acceptIdentifier(registerDesc)) {
3600 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003601 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003602 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003603 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3604 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003605 // Then we didn't really see the registerDesc yet, it was
3606 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003607 profile = registerDesc;
3608 if (! acceptIdentifier(registerDesc)) {
3609 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003610 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003611 }
3612 }
John Kessenichb38f0712016-07-30 10:29:54 -06003613 int subComponent = 0;
3614 if (acceptTokenClass(EHTokLeftBracket)) {
3615 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3616 if (! peekTokenClass(EHTokIntConstant)) {
3617 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003618 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003619 }
3620 subComponent = token.i;
3621 advanceToken();
3622 if (! acceptTokenClass(EHTokRightBracket)) {
3623 expected("]");
3624 break;
3625 }
3626 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003627 // (COMMA SPACEN)opt
3628 HlslToken spaceDesc;
3629 if (acceptTokenClass(EHTokComma)) {
3630 if (! acceptIdentifier(spaceDesc)) {
3631 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003632 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003633 }
3634 }
3635 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003636 if (! acceptTokenClass(EHTokRightParen)) {
3637 expected(")");
3638 break;
3639 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003640 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003641 } else {
3642 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003643 TString semanticUpperCase = *idToken.string;
3644 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3645 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003646 }
John Kessenich854fe242017-03-02 14:30:59 -07003647 } else if (peekTokenClass(EHTokLeftAngle)) {
3648 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003649 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003650 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003651 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003652
John Kessenich630dd7d2016-06-12 23:52:12 -06003653 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003654
3655 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003656}
3657
John Kessenichb16f7e62017-03-11 19:32:47 -07003658//
3659// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3660// processing.
3661//
3662bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3663{
3664 if (! peekTokenClass(EHTokLeftBrace))
3665 return false;
3666
3667 int braceCount = 0;
3668
3669 do {
3670 switch (peek()) {
3671 case EHTokLeftBrace:
3672 ++braceCount;
3673 break;
3674 case EHTokRightBrace:
3675 --braceCount;
3676 break;
3677 case EHTokNone:
3678 // End of input before balance { } is bad...
3679 return false;
3680 default:
3681 break;
3682 }
3683
3684 tokens.push_back(token);
3685 advanceToken();
3686 } while (braceCount > 0);
3687
3688 return true;
3689}
3690
John Kesseniche01a9bc2016-03-12 20:11:22 -07003691} // end namespace glslang