blob: 3891734a430804d65b38ffff3f8810e53dca3be6 [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 Kessenichaecd4972016-03-14 10:46:34 -060078// Only process the next token if it is an identifier.
79// Return true if it was an identifier.
80bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
81{
82 if (peekTokenClass(EHTokIdentifier)) {
83 idToken = token;
84 advanceToken();
85 return true;
86 }
87
steve-lunarg5ca85ad2016-12-26 18:45:52 -070088 // Even though "sample", "bool", "float", etc keywords (for types, interpolation modifiers),
89 // they ARE still accepted as identifiers. This is not a dense space: e.g, "void" is not a
90 // valid identifier, nor is "linear". This code special cases the known instances of this, so
91 // e.g, "int sample;" or "float float;" is accepted. Other cases can be added here if needed.
John Kessenichecba76f2017-01-06 00:34:48 -070092
steve-lunarg5ca85ad2016-12-26 18:45:52 -070093 TString* idString = nullptr;
94 switch (peek()) {
95 case EHTokSample: idString = NewPoolTString("sample"); break;
96 case EHTokHalf: idString = NewPoolTString("half"); break;
97 case EHTokBool: idString = NewPoolTString("bool"); break;
98 case EHTokFloat: idString = NewPoolTString("float"); break;
99 case EHTokDouble: idString = NewPoolTString("double"); break;
100 case EHTokInt: idString = NewPoolTString("int"); break;
101 case EHTokUint: idString = NewPoolTString("uint"); break;
102 case EHTokMin16float: idString = NewPoolTString("min16float"); break;
103 case EHTokMin10float: idString = NewPoolTString("min10float"); break;
104 case EHTokMin16int: idString = NewPoolTString("min16int"); break;
105 case EHTokMin12int: idString = NewPoolTString("min12int"); break;
106 default:
107 return false;
steve-lunarg75fd2232016-11-16 13:22:11 -0700108 }
109
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700110 token.string = idString;
111 token.tokenClass = EHTokIdentifier;
112 token.symbol = nullptr;
113 idToken = token;
114
115 advanceToken();
116
117 return true;
John Kessenichaecd4972016-03-14 10:46:34 -0600118}
119
John Kesseniche01a9bc2016-03-12 20:11:22 -0700120// compilationUnit
121// : list of externalDeclaration
steve-lunargcb88de52016-08-03 07:04:18 -0600122// | SEMICOLONS
John Kesseniche01a9bc2016-03-12 20:11:22 -0700123//
124bool HlslGrammar::acceptCompilationUnit()
125{
John Kessenichd016be12016-03-13 11:24:20 -0600126 TIntermNode* unitNode = nullptr;
127
John Kessenich9c86c6a2016-05-03 22:49:24 -0600128 while (! peekTokenClass(EHTokNone)) {
steve-lunargcb88de52016-08-03 07:04:18 -0600129 // HLSL allows semicolons between global declarations, e.g, between functions.
130 if (acceptTokenClass(EHTokSemicolon))
131 continue;
132
John Kessenichd016be12016-03-13 11:24:20 -0600133 // externalDeclaration
John Kessenichca71d942017-03-07 20:44:09 -0700134 if (! acceptDeclaration(unitNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -0700135 return false;
136 }
137
John Kessenichd016be12016-03-13 11:24:20 -0600138 // set root of AST
John Kessenichca71d942017-03-07 20:44:09 -0700139 if (unitNode && !unitNode->getAsAggregate())
140 unitNode = intermediate.growAggregate(nullptr, unitNode);
John Kessenich078d7f22016-03-14 10:02:11 -0600141 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600142
John Kesseniche01a9bc2016-03-12 20:11:22 -0700143 return true;
144}
145
LoopDawg4886f692016-06-29 10:58:58 -0600146// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700147// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600148//
149// sampler_state_assignment
150// : sampler_state_identifier EQUAL value SEMICOLON
151//
152// sampler_state_identifier
153// : ADDRESSU
154// | ADDRESSV
155// | ADDRESSW
156// | BORDERCOLOR
157// | FILTER
158// | MAXANISOTROPY
159// | MAXLOD
160// | MINLOD
161// | MIPLODBIAS
162//
163bool HlslGrammar::acceptSamplerState()
164{
165 // TODO: this should be genericized to accept a list of valid tokens and
166 // return token/value pairs. Presently it is specific to texture values.
167
168 if (! acceptTokenClass(EHTokLeftBrace))
169 return true;
170
171 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700172
LoopDawg4886f692016-06-29 10:58:58 -0600173 do {
174 // read state name
175 HlslToken state;
176 if (! acceptIdentifier(state))
177 break; // end of list
178
179 // FXC accepts any case
180 TString stateName = *state.string;
181 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
182
183 if (! acceptTokenClass(EHTokAssign)) {
184 expected("assign");
185 return false;
186 }
187
188 if (stateName == "minlod" || stateName == "maxlod") {
189 if (! peekTokenClass(EHTokIntConstant)) {
190 expected("integer");
191 return false;
192 }
193
194 TIntermTyped* lod = nullptr;
195 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
196 return false;
197 } else if (stateName == "maxanisotropy") {
198 if (! peekTokenClass(EHTokIntConstant)) {
199 expected("integer");
200 return false;
201 }
202
203 TIntermTyped* maxAnisotropy = nullptr;
204 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
205 return false;
206 } else if (stateName == "filter") {
207 HlslToken filterMode;
208 if (! acceptIdentifier(filterMode)) {
209 expected("filter mode");
210 return false;
211 }
212 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
213 HlslToken addrMode;
214 if (! acceptIdentifier(addrMode)) {
215 expected("texture address mode");
216 return false;
217 }
218 } else if (stateName == "miplodbias") {
219 TIntermTyped* lodBias = nullptr;
220 if (! acceptLiteral(lodBias)) {
221 expected("lod bias");
222 return false;
223 }
224 } else if (stateName == "bordercolor") {
225 return false;
226 } else {
227 expected("texture state");
228 return false;
229 }
230
231 // SEMICOLON
232 if (! acceptTokenClass(EHTokSemicolon)) {
233 expected("semicolon");
234 return false;
235 }
236 } while (true);
237
238 if (! acceptTokenClass(EHTokRightBrace))
239 return false;
240
241 return true;
242}
243
244// sampler_declaration_dx9
245// : SAMPLER identifier EQUAL sampler_type sampler_state
246//
John Kesseniche4821e42016-07-16 10:19:43 -0600247bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600248{
249 if (! acceptTokenClass(EHTokSampler))
250 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700251
LoopDawg4886f692016-06-29 10:58:58 -0600252 // TODO: remove this when DX9 style declarations are implemented.
253 unimplemented("Direct3D 9 sampler declaration");
254
255 // read sampler name
256 HlslToken name;
257 if (! acceptIdentifier(name)) {
258 expected("sampler name");
259 return false;
260 }
261
262 if (! acceptTokenClass(EHTokAssign)) {
263 expected("=");
264 return false;
265 }
266
267 return false;
268}
269
John Kesseniche01a9bc2016-03-12 20:11:22 -0700270// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600271// : sampler_declaration_dx9 post_decls SEMICOLON
272// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600273// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600274// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600275// | typedef declaration
John Kessenich87142c72016-03-12 20:24:24 -0700276//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600277// declarator_list
278// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600279//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600280// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600281// : identifier array_specifier post_decls
282// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600283// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600284//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600285// Parsing has to go pretty far in to know whether it's a variable, prototype, or
286// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600287// as above. (The 'identifier' in the first item in init_declarator list is the
288// same as 'identifier' for function declarations.)
289//
John Kessenichca71d942017-03-07 20:44:09 -0700290// This can generate more than one subtree, one per initializer or a function body.
291// All initializer subtrees are put in their own aggregate node, making one top-level
292// node for all the initializers. Each function created is a top-level node to grow
293// into the passed-in nodeList.
John Kessenichd016be12016-03-13 11:24:20 -0600294//
John Kessenichca71d942017-03-07 20:44:09 -0700295// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
296// each top-level node the declaration creates. Otherwise, if only one top-level
297// node in generated here, that is want is returned in nodeList.
John Kessenich02467d82017-01-19 15:41:47 -0700298//
John Kessenichca71d942017-03-07 20:44:09 -0700299bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700300{
John Kessenich54ee28f2017-03-11 14:13:00 -0700301 bool declarator_list = false; // true when processing comma separation
John Kessenichd016be12016-03-13 11:24:20 -0600302
steve-lunarg1868b142016-10-20 13:07:10 -0600303 // attributes
John Kessenich088d52b2017-03-11 17:55:28 -0700304 TFunctionDeclarator declarator;
305 acceptAttributes(declarator.attributes);
steve-lunarg1868b142016-10-20 13:07:10 -0600306
John Kessenich5e69ec62016-07-05 00:02:40 -0600307 // typedef
308 bool typedefDecl = acceptTokenClass(EHTokTypedef);
309
John Kesseniche82061d2016-09-27 14:38:57 -0600310 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600311
312 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600313 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
314 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
315 // HLSL shaders, this will have to be a master level switch
316 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700317 // For that reason, this line is commented out
John Kessenichca71d942017-03-07 20:44:09 -0700318 // if (acceptSamplerDeclarationDX9(declaredType))
319 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600320
321 // fully_specified_type
John Kessenich54ee28f2017-03-11 14:13:00 -0700322 if (! acceptFullySpecifiedType(declaredType, nodeList))
John Kessenich87142c72016-03-12 20:24:24 -0700323 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600324
John Kessenich87142c72016-03-12 20:24:24 -0700325 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600326 HlslToken idToken;
John Kessenichca71d942017-03-07 20:44:09 -0700327 TIntermAggregate* initializers = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600328 while (acceptIdentifier(idToken)) {
John Kessenich78388722017-03-08 18:53:51 -0700329 if (peekTokenClass(EHTokLeftParen)) {
330 // looks like function parameters
331 TString* fnName = idToken.string;
steve-lunargf1e0c872016-10-31 15:13:43 -0600332
John Kessenich78388722017-03-08 18:53:51 -0700333 // Potentially rename shader entry point function. No-op most of the time.
334 parseContext.renameShaderFunction(fnName);
steve-lunargf1e0c872016-10-31 15:13:43 -0600335
John Kessenich78388722017-03-08 18:53:51 -0700336 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -0700337 declarator.function = new TFunction(fnName, declaredType);
338 if (!acceptFunctionParameters(*declarator.function)) {
John Kessenich78388722017-03-08 18:53:51 -0700339 expected("function parameter list");
340 return false;
341 }
342
John Kessenich630dd7d2016-06-12 23:52:12 -0600343 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -0700344 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600345
John Kessenichd5ed0b62016-07-04 17:32:45 -0600346 // compound_statement (function body definition) or just a prototype?
John Kessenich088d52b2017-03-11 17:55:28 -0700347 declarator.loc = token.loc;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600348 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700349 if (declarator_list)
John Kessenichd5ed0b62016-07-04 17:32:45 -0600350 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600351 if (typedefDecl)
352 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenichb16f7e62017-03-11 19:32:47 -0700353 return acceptFunctionDefinition(declarator, nodeList, nullptr);
John Kessenich5e69ec62016-07-05 00:02:40 -0600354 } else {
355 if (typedefDecl)
356 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich088d52b2017-03-11 17:55:28 -0700357 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600358 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600359 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600360 // A variable declaration. Fix the storage qualifier if it's a global.
361 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
362 declaredType.getQualifier().storage = EvqUniform;
363
John Kessenichecba76f2017-01-06 00:34:48 -0700364 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600365 // the number of types can expand when arrayness is different.
366 TType variableType;
367 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600368
John Kesseniche82061d2016-09-27 14:38:57 -0600369 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600370 TArraySizes* arraySizes = nullptr;
371 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600372
John Kesseniche82061d2016-09-27 14:38:57 -0600373 // Fix arrayness in the variableType
374 if (declaredType.isImplicitlySizedArray()) {
375 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
376 // of different sizes, for this case sharing the shallow copy of arrayness
377 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
378 variableType.newArraySizes(declaredType.getArraySizes());
379 }
380 if (arraySizes || variableType.isArray()) {
381 // In the most general case, arrayness is potentially coming both from the
382 // declared type and from the variable: "int[] a[];" or just one or the other.
383 // Merge it all to the variableType, so all arrayness is part of the variableType.
384 parseContext.arrayDimMerge(variableType, arraySizes);
385 }
386
LoopDawg4886f692016-06-29 10:58:58 -0600387 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600388 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600389 if (! acceptSamplerState())
390 return false;
391 }
392
John Kessenichd5ed0b62016-07-04 17:32:45 -0600393 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600394 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600395
396 // EQUAL assignment_expression
397 TIntermTyped* expressionNode = nullptr;
398 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600399 if (typedefDecl)
400 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600401 if (! acceptAssignmentExpression(expressionNode)) {
402 expected("initializer");
403 return false;
404 }
405 }
406
John Kessenich6dbc0a72016-09-27 19:13:05 -0600407 // TODO: things scoped within an annotation need their own name space;
408 // TODO: strings are not yet handled.
409 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
410 if (typedefDecl)
411 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
412 else if (variableType.getBasicType() == EbtBlock)
steve-lunargdd8287a2017-02-23 18:04:12 -0700413 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600414 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700415 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600416 // this isn't really an individual variable, but a member of the $Global buffer
417 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
418 } else {
419 // Declare the variable and add any initializer code to the AST.
420 // The top-level node is always made into an aggregate, as that's
421 // historically how the AST has been.
John Kessenichca71d942017-03-07 20:44:09 -0700422 initializers = intermediate.growAggregate(initializers,
423 parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
424 idToken.loc);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600425 }
426 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600427 }
John Kessenich5f934b02016-03-13 17:58:25 -0600428 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600429
430 if (acceptTokenClass(EHTokComma)) {
John Kessenich54ee28f2017-03-11 14:13:00 -0700431 declarator_list = true;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600432 continue;
433 }
434 };
435
John Kessenichca71d942017-03-07 20:44:09 -0700436 // The top-level initializer node is a sequence.
437 if (initializers != nullptr)
438 initializers->setOperator(EOpSequence);
439
440 // Add the initializers' aggregate to the nodeList we were handed.
441 if (nodeList)
442 nodeList = intermediate.growAggregate(nodeList, initializers);
443 else
444 nodeList = initializers;
John Kessenich87142c72016-03-12 20:24:24 -0700445
John Kessenich078d7f22016-03-14 10:02:11 -0600446 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600447 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700448 // This may have been a false detection of what appeared to be a declaration, but
449 // was actually an assignment such as "float = 4", where "float" is an identifier.
450 // We put the token back to let further parsing happen for cases where that may
451 // happen. This errors on the side of caution, and mostly triggers the error.
452
453 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
454 recedeToken();
455 else
456 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600457 return false;
458 }
John Kessenichecba76f2017-01-06 00:34:48 -0700459
John Kesseniche01a9bc2016-03-12 20:11:22 -0700460 return true;
461}
462
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600463// control_declaration
464// : fully_specified_type identifier EQUAL expression
465//
466bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
467{
468 node = nullptr;
469
470 // fully_specified_type
471 TType type;
472 if (! acceptFullySpecifiedType(type))
473 return false;
474
John Kessenich057df292017-03-06 18:18:37 -0700475 // filter out type casts
476 if (peekTokenClass(EHTokLeftParen)) {
477 recedeToken();
478 return false;
479 }
480
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600481 // identifier
482 HlslToken idToken;
483 if (! acceptIdentifier(idToken)) {
484 expected("identifier");
485 return false;
486 }
487
488 // EQUAL
489 TIntermTyped* expressionNode = nullptr;
490 if (! acceptTokenClass(EHTokAssign)) {
491 expected("=");
492 return false;
493 }
494
495 // expression
496 if (! acceptExpression(expressionNode)) {
497 expected("initializer");
498 return false;
499 }
500
John Kesseniche82061d2016-09-27 14:38:57 -0600501 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600502
503 return true;
504}
505
John Kessenich87142c72016-03-12 20:24:24 -0700506// fully_specified_type
507// : type_specifier
508// | type_qualifier type_specifier
509//
510bool HlslGrammar::acceptFullySpecifiedType(TType& type)
511{
John Kessenich54ee28f2017-03-11 14:13:00 -0700512 TIntermNode* nodeList = nullptr;
513 return acceptFullySpecifiedType(type, nodeList);
514}
515bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList)
516{
John Kessenich87142c72016-03-12 20:24:24 -0700517 // type_qualifier
518 TQualifier qualifier;
519 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600520 if (! acceptQualifier(qualifier))
521 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600522 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700523
524 // type_specifier
John Kessenich54ee28f2017-03-11 14:13:00 -0700525 if (! acceptType(type, nodeList)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -0700526 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700527 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700528 // qualifier. Back it out, if we did.
529 if (qualifier.sample)
530 recedeToken();
531
John Kessenich87142c72016-03-12 20:24:24 -0700532 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700533 }
John Kessenich3d157c52016-07-25 16:05:33 -0600534 if (type.getBasicType() == EbtBlock) {
535 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600536 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600537 // further, it can create an anonymous instance of the block
538 if (peekTokenClass(EHTokSemicolon))
539 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600540 } else {
541 // Some qualifiers are set when parsing the type. Merge those with
542 // whatever comes from acceptQualifier.
543 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700544
steve-lunargbb0183f2016-10-04 16:58:14 -0600545 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600546 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700547
steve-lunarg5da1f032017-02-12 17:50:28 -0700548 if (type.getQualifier().storage == EvqVaryingOut ||
549 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700550 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700551 qualifier.readonly = type.getQualifier().readonly;
552 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700553
554 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600555 }
John Kessenich87142c72016-03-12 20:24:24 -0700556
557 return true;
558}
559
John Kessenich630dd7d2016-06-12 23:52:12 -0600560// type_qualifier
561// : qualifier qualifier ...
562//
563// Zero or more of these, so this can't return false.
564//
John Kessenichb9e39122016-08-17 10:22:08 -0600565bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700566{
John Kessenich630dd7d2016-06-12 23:52:12 -0600567 do {
568 switch (peek()) {
569 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600570 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600571 break;
572 case EHTokExtern:
573 // TODO: no meaning in glslang?
574 break;
575 case EHTokShared:
576 // TODO: hint
577 break;
578 case EHTokGroupShared:
579 qualifier.storage = EvqShared;
580 break;
581 case EHTokUniform:
582 qualifier.storage = EvqUniform;
583 break;
584 case EHTokConst:
585 qualifier.storage = EvqConst;
586 break;
587 case EHTokVolatile:
588 qualifier.volatil = true;
589 break;
590 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600591 qualifier.smooth = true;
592 break;
593 case EHTokCentroid:
594 qualifier.centroid = true;
595 break;
596 case EHTokNointerpolation:
597 qualifier.flat = true;
598 break;
599 case EHTokNoperspective:
600 qualifier.nopersp = true;
601 break;
602 case EHTokSample:
603 qualifier.sample = true;
604 break;
605 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600606 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600607 break;
608 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600609 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600610 break;
611 case EHTokPrecise:
612 qualifier.noContraction = true;
613 break;
LoopDawg9249c702016-07-12 20:44:32 -0600614 case EHTokIn:
615 qualifier.storage = EvqIn;
616 break;
617 case EHTokOut:
618 qualifier.storage = EvqOut;
619 break;
620 case EHTokInOut:
621 qualifier.storage = EvqInOut;
622 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600623 case EHTokLayout:
624 if (! acceptLayoutQualifierList(qualifier))
625 return false;
626 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700627 case EHTokGloballyCoherent:
628 qualifier.coherent = true;
629 break;
John Kessenich36b218d2017-03-15 09:05:14 -0600630 case EHTokInline:
631 // TODO: map this to SPIR-V function control
632 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700633
634 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
635 // for output variables.
636 case EHTokPoint:
637 qualifier.storage = EvqIn;
638 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
639 return false;
640 break;
641 case EHTokLine:
642 qualifier.storage = EvqIn;
643 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
644 return false;
645 break;
646 case EHTokTriangle:
647 qualifier.storage = EvqIn;
648 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
649 return false;
650 break;
651 case EHTokLineAdj:
652 qualifier.storage = EvqIn;
653 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
654 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700655 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700656 case EHTokTriangleAdj:
657 qualifier.storage = EvqIn;
658 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
659 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700660 break;
661
John Kessenich630dd7d2016-06-12 23:52:12 -0600662 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600663 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600664 }
665 advanceToken();
666 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700667}
668
John Kessenichb9e39122016-08-17 10:22:08 -0600669// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600670// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600671//
672// layout_qualifier
673// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600674// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600675//
676// Zero or more of these, so this can't return false.
677//
678bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
679{
680 if (! acceptTokenClass(EHTokLayout))
681 return false;
682
683 // LEFT_PAREN
684 if (! acceptTokenClass(EHTokLeftParen))
685 return false;
686
687 do {
688 // identifier
689 HlslToken idToken;
690 if (! acceptIdentifier(idToken))
691 break;
692
693 // EQUAL expression
694 if (acceptTokenClass(EHTokAssign)) {
695 TIntermTyped* expr;
696 if (! acceptConditionalExpression(expr)) {
697 expected("expression");
698 return false;
699 }
700 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
701 } else
702 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
703
704 // COMMA
705 if (! acceptTokenClass(EHTokComma))
706 break;
707 } while (true);
708
709 // RIGHT_PAREN
710 if (! acceptTokenClass(EHTokRightParen)) {
711 expected(")");
712 return false;
713 }
714
715 return true;
716}
717
LoopDawg6daaa4f2016-06-23 19:13:48 -0600718// template_type
719// : FLOAT
720// | DOUBLE
721// | INT
722// | DWORD
723// | UINT
724// | BOOL
725//
steve-lunargf49cdf42016-11-17 15:04:20 -0700726bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600727{
728 switch (peek()) {
729 case EHTokFloat:
730 basicType = EbtFloat;
731 break;
732 case EHTokDouble:
733 basicType = EbtDouble;
734 break;
735 case EHTokInt:
736 case EHTokDword:
737 basicType = EbtInt;
738 break;
739 case EHTokUint:
740 basicType = EbtUint;
741 break;
742 case EHTokBool:
743 basicType = EbtBool;
744 break;
745 default:
746 return false;
747 }
748
749 advanceToken();
750
751 return true;
752}
753
754// vector_template_type
755// : VECTOR
756// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
757//
758bool HlslGrammar::acceptVectorTemplateType(TType& type)
759{
760 if (! acceptTokenClass(EHTokVector))
761 return false;
762
763 if (! acceptTokenClass(EHTokLeftAngle)) {
764 // in HLSL, 'vector' alone means float4.
765 new(&type) TType(EbtFloat, EvqTemporary, 4);
766 return true;
767 }
768
769 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700770 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600771 expected("scalar type");
772 return false;
773 }
774
775 // COMMA
776 if (! acceptTokenClass(EHTokComma)) {
777 expected(",");
778 return false;
779 }
780
781 // integer
782 if (! peekTokenClass(EHTokIntConstant)) {
783 expected("literal integer");
784 return false;
785 }
786
787 TIntermTyped* vecSize;
788 if (! acceptLiteral(vecSize))
789 return false;
790
791 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
792
793 new(&type) TType(basicType, EvqTemporary, vecSizeI);
794
795 if (vecSizeI == 1)
796 type.makeVector();
797
798 if (!acceptTokenClass(EHTokRightAngle)) {
799 expected("right angle bracket");
800 return false;
801 }
802
803 return true;
804}
805
806// matrix_template_type
807// : MATRIX
808// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
809//
810bool HlslGrammar::acceptMatrixTemplateType(TType& type)
811{
812 if (! acceptTokenClass(EHTokMatrix))
813 return false;
814
815 if (! acceptTokenClass(EHTokLeftAngle)) {
816 // in HLSL, 'matrix' alone means float4x4.
817 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
818 return true;
819 }
820
821 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700822 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600823 expected("scalar type");
824 return false;
825 }
826
827 // COMMA
828 if (! acceptTokenClass(EHTokComma)) {
829 expected(",");
830 return false;
831 }
832
833 // integer rows
834 if (! peekTokenClass(EHTokIntConstant)) {
835 expected("literal integer");
836 return false;
837 }
838
839 TIntermTyped* rows;
840 if (! acceptLiteral(rows))
841 return false;
842
843 // COMMA
844 if (! acceptTokenClass(EHTokComma)) {
845 expected(",");
846 return false;
847 }
John Kessenichecba76f2017-01-06 00:34:48 -0700848
LoopDawg6daaa4f2016-06-23 19:13:48 -0600849 // integer cols
850 if (! peekTokenClass(EHTokIntConstant)) {
851 expected("literal integer");
852 return false;
853 }
854
855 TIntermTyped* cols;
856 if (! acceptLiteral(cols))
857 return false;
858
859 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600860 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
861 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600862
863 if (!acceptTokenClass(EHTokRightAngle)) {
864 expected("right angle bracket");
865 return false;
866 }
867
868 return true;
869}
870
steve-lunargf49cdf42016-11-17 15:04:20 -0700871// layout_geometry
872// : LINESTREAM
873// | POINTSTREAM
874// | TRIANGLESTREAM
875//
876bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
877{
878 // read geometry type
879 const EHlslTokenClass geometryType = peek();
880
881 switch (geometryType) {
882 case EHTokPointStream: geometry = ElgPoints; break;
883 case EHTokLineStream: geometry = ElgLineStrip; break;
884 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
885 default:
886 return false; // not a layout geometry
887 }
888
889 advanceToken(); // consume the layout keyword
890 return true;
891}
892
steve-lunarg858c9282017-01-07 08:54:10 -0700893// tessellation_decl_type
894// : INPUTPATCH
895// | OUTPUTPATCH
896//
897bool HlslGrammar::acceptTessellationDeclType()
898{
899 // read geometry type
900 const EHlslTokenClass tessType = peek();
901
902 switch (tessType) {
903 case EHTokInputPatch: break;
904 case EHTokOutputPatch: break;
905 default:
906 return false; // not a tessellation decl
907 }
908
909 advanceToken(); // consume the keyword
910 return true;
911}
912
913// tessellation_patch_template_type
914// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
915//
916bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
917{
918 if (! acceptTessellationDeclType())
919 return false;
920
921 if (! acceptTokenClass(EHTokLeftAngle))
922 return false;
923
924 if (! acceptType(type)) {
925 expected("tessellation patch type");
926 return false;
927 }
928
929 if (! acceptTokenClass(EHTokComma))
930 return false;
931
932 // integer size
933 if (! peekTokenClass(EHTokIntConstant)) {
934 expected("literal integer");
935 return false;
936 }
937
938 TIntermTyped* size;
939 if (! acceptLiteral(size))
940 return false;
941
942 TArraySizes* arraySizes = new TArraySizes;
943 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
944 type.newArraySizes(*arraySizes);
945
946 if (! acceptTokenClass(EHTokRightAngle)) {
947 expected("right angle bracket");
948 return false;
949 }
950
951 return true;
952}
953
steve-lunargf49cdf42016-11-17 15:04:20 -0700954// stream_out_template_type
955// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
956//
957bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
958{
959 geometry = ElgNone;
960
961 if (! acceptOutputPrimitiveGeometry(geometry))
962 return false;
963
964 if (! acceptTokenClass(EHTokLeftAngle))
965 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700966
steve-lunargf49cdf42016-11-17 15:04:20 -0700967 if (! acceptType(type)) {
968 expected("stream output type");
969 return false;
970 }
971
972 type.getQualifier().storage = EvqVaryingOut;
973
974 if (! acceptTokenClass(EHTokRightAngle)) {
975 expected("right angle bracket");
976 return false;
977 }
978
979 return true;
980}
John Kessenichecba76f2017-01-06 00:34:48 -0700981
John Kessenicha1e2d492016-09-20 13:22:58 -0600982// annotations
983// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600984//
John Kessenicha1e2d492016-09-20 13:22:58 -0600985bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600986{
John Kessenicha1e2d492016-09-20 13:22:58 -0600987 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600988 return false;
989
John Kessenicha1e2d492016-09-20 13:22:58 -0600990 // note that we are nesting a name space
991 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600992
993 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
994 do {
995 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
996 while (acceptTokenClass(EHTokSemicolon))
997 ;
998
999 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -06001000 break;
John Kessenich86f71382016-09-19 20:23:18 -06001001
1002 // declaration
John Kessenichca71d942017-03-07 20:44:09 -07001003 TIntermNode* node = nullptr;
John Kessenich86f71382016-09-19 20:23:18 -06001004 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -06001005 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -06001006 return false;
1007 }
1008 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -06001009
1010 parseContext.unnestAnnotations();
1011 return true;
John Kessenich86f71382016-09-19 20:23:18 -06001012}
LoopDawg6daaa4f2016-06-23 19:13:48 -06001013
LoopDawg4886f692016-06-29 10:58:58 -06001014// sampler_type
1015// : SAMPLER
1016// | SAMPLER1D
1017// | SAMPLER2D
1018// | SAMPLER3D
1019// | SAMPLERCUBE
1020// | SAMPLERSTATE
1021// | SAMPLERCOMPARISONSTATE
1022bool HlslGrammar::acceptSamplerType(TType& type)
1023{
1024 // read sampler type
1025 const EHlslTokenClass samplerType = peek();
1026
LoopDawga78b0292016-07-19 14:28:05 -06001027 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001028 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001029
LoopDawga78b0292016-07-19 14:28:05 -06001030 bool isShadow = false;
1031
LoopDawg4886f692016-06-29 10:58:58 -06001032 switch (samplerType) {
1033 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001034 case EHTokSampler1d: /*dim = Esd1D*/; break;
1035 case EHTokSampler2d: /*dim = Esd2D*/; break;
1036 case EHTokSampler3d: /*dim = Esd3D*/; break;
1037 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001038 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001039 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001040 default:
1041 return false; // not a sampler declaration
1042 }
1043
1044 advanceToken(); // consume the sampler type keyword
1045
1046 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001047
1048 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001049 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001050
1051 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1052
1053 return true;
1054}
1055
1056// texture_type
1057// | BUFFER
1058// | TEXTURE1D
1059// | TEXTURE1DARRAY
1060// | TEXTURE2D
1061// | TEXTURE2DARRAY
1062// | TEXTURE3D
1063// | TEXTURECUBE
1064// | TEXTURECUBEARRAY
1065// | TEXTURE2DMS
1066// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001067// | RWBUFFER
1068// | RWTEXTURE1D
1069// | RWTEXTURE1DARRAY
1070// | RWTEXTURE2D
1071// | RWTEXTURE2DARRAY
1072// | RWTEXTURE3D
1073
LoopDawg4886f692016-06-29 10:58:58 -06001074bool HlslGrammar::acceptTextureType(TType& type)
1075{
1076 const EHlslTokenClass textureType = peek();
1077
1078 TSamplerDim dim = EsdNone;
1079 bool array = false;
1080 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001081 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -06001082
1083 switch (textureType) {
1084 case EHTokBuffer: dim = EsdBuffer; break;
1085 case EHTokTexture1d: dim = Esd1D; break;
1086 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1087 case EHTokTexture2d: dim = Esd2D; break;
1088 case EHTokTexture2darray: dim = Esd2D; array = true; break;
John Kessenichecba76f2017-01-06 00:34:48 -07001089 case EHTokTexture3d: dim = Esd3D; break;
LoopDawg4886f692016-06-29 10:58:58 -06001090 case EHTokTextureCube: dim = EsdCube; break;
1091 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1092 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1093 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001094 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1095 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1096 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1097 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1098 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1099 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001100 default:
1101 return false; // not a texture declaration
1102 }
1103
1104 advanceToken(); // consume the texture object keyword
1105
1106 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001107
LoopDawg4886f692016-06-29 10:58:58 -06001108 TIntermTyped* msCount = nullptr;
1109
steve-lunargbb0183f2016-10-04 16:58:14 -06001110 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001111 if (acceptTokenClass(EHTokLeftAngle)) {
1112 if (! acceptType(txType)) {
1113 expected("scalar or vector type");
1114 return false;
1115 }
1116
1117 const TBasicType basicRetType = txType.getBasicType() ;
1118
1119 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1120 unimplemented("basic type in texture");
1121 return false;
1122 }
1123
steve-lunargd53f7172016-07-27 15:46:48 -06001124 // Buffers can handle small mats if they fit in 4 components
1125 if (dim == EsdBuffer && txType.isMatrix()) {
1126 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1127 expected("components < 4 in matrix buffer type");
1128 return false;
1129 }
1130
1131 // TODO: except we don't handle it yet...
1132 unimplemented("matrix type in buffer");
1133 return false;
1134 }
1135
LoopDawg4886f692016-06-29 10:58:58 -06001136 if (!txType.isScalar() && !txType.isVector()) {
1137 expected("scalar or vector type");
1138 return false;
1139 }
1140
LoopDawg4886f692016-06-29 10:58:58 -06001141 if (ms && acceptTokenClass(EHTokComma)) {
1142 // read sample count for multisample types, if given
1143 if (! peekTokenClass(EHTokIntConstant)) {
1144 expected("multisample count");
1145 return false;
1146 }
1147
1148 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1149 return false;
1150 }
1151
1152 if (! acceptTokenClass(EHTokRightAngle)) {
1153 expected("right angle bracket");
1154 return false;
1155 }
1156 } else if (ms) {
1157 expected("texture type for multisample");
1158 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001159 } else if (image) {
1160 expected("type for RWTexture/RWBuffer");
1161 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001162 }
1163
1164 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001165 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001166
1167 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001168 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001169
steve-lunarg4f2da272016-10-10 15:24:57 -06001170 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1171 if (image || dim == EsdBuffer)
1172 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001173
1174 // Non-image Buffers are combined
1175 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001176 sampler.set(txType.getBasicType(), dim, array);
1177 } else {
1178 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001179 if (image) {
1180 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1181 } else {
1182 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1183 }
steve-lunargd53f7172016-07-27 15:46:48 -06001184 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001185
1186 // Remember the declared vector size.
1187 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001188
LoopDawg4886f692016-06-29 10:58:58 -06001189 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001190 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001191
1192 return true;
1193}
1194
John Kessenich87142c72016-03-12 20:24:24 -07001195// If token is for a type, update 'type' with the type information,
1196// and return true and advance.
1197// Otherwise, return false, and don't advance
1198bool HlslGrammar::acceptType(TType& type)
1199{
John Kessenich54ee28f2017-03-11 14:13:00 -07001200 TIntermNode* nodeList = nullptr;
1201 return acceptType(type, nodeList);
1202}
1203bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
1204{
steve-lunarg3226b082016-10-26 19:18:55 -06001205 // Basic types for min* types, broken out here in case of future
1206 // changes, e.g, to use native halfs.
1207 static const TBasicType min16float_bt = EbtFloat;
1208 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001209 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001210 static const TBasicType min16int_bt = EbtInt;
1211 static const TBasicType min12int_bt = EbtInt;
1212 static const TBasicType min16uint_bt = EbtUint;
1213
John Kessenich9c86c6a2016-05-03 22:49:24 -06001214 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001215 case EHTokVector:
1216 return acceptVectorTemplateType(type);
1217 break;
1218
1219 case EHTokMatrix:
1220 return acceptMatrixTemplateType(type);
1221 break;
1222
steve-lunargf49cdf42016-11-17 15:04:20 -07001223 case EHTokPointStream: // fall through
1224 case EHTokLineStream: // ...
1225 case EHTokTriangleStream: // ...
1226 {
1227 TLayoutGeometry geometry;
1228 if (! acceptStreamOutTemplateType(type, geometry))
1229 return false;
1230
1231 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1232 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001233
steve-lunargf49cdf42016-11-17 15:04:20 -07001234 return true;
1235 }
1236
steve-lunarg858c9282017-01-07 08:54:10 -07001237 case EHTokInputPatch: // fall through
1238 case EHTokOutputPatch: // ...
1239 {
1240 if (! acceptTessellationPatchTemplateType(type))
1241 return false;
1242
1243 return true;
1244 }
1245
LoopDawg4886f692016-06-29 10:58:58 -06001246 case EHTokSampler: // fall through
1247 case EHTokSampler1d: // ...
1248 case EHTokSampler2d: // ...
1249 case EHTokSampler3d: // ...
1250 case EHTokSamplerCube: // ...
1251 case EHTokSamplerState: // ...
1252 case EHTokSamplerComparisonState: // ...
1253 return acceptSamplerType(type);
1254 break;
1255
1256 case EHTokBuffer: // fall through
1257 case EHTokTexture1d: // ...
1258 case EHTokTexture1darray: // ...
1259 case EHTokTexture2d: // ...
1260 case EHTokTexture2darray: // ...
1261 case EHTokTexture3d: // ...
1262 case EHTokTextureCube: // ...
1263 case EHTokTextureCubearray: // ...
1264 case EHTokTexture2DMS: // ...
1265 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001266 case EHTokRWTexture1d: // ...
1267 case EHTokRWTexture1darray: // ...
1268 case EHTokRWTexture2d: // ...
1269 case EHTokRWTexture2darray: // ...
1270 case EHTokRWTexture3d: // ...
1271 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001272 return acceptTextureType(type);
1273 break;
1274
steve-lunarg5da1f032017-02-12 17:50:28 -07001275 case EHTokAppendStructuredBuffer:
1276 case EHTokByteAddressBuffer:
1277 case EHTokConsumeStructuredBuffer:
1278 case EHTokRWByteAddressBuffer:
1279 case EHTokRWStructuredBuffer:
1280 case EHTokStructuredBuffer:
1281 return acceptStructBufferType(type);
1282 break;
1283
John Kessenich27ffb292017-03-03 17:01:01 -07001284 case EHTokClass:
John Kesseniche6e74942016-06-11 16:43:14 -06001285 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001286 case EHTokCBuffer:
1287 case EHTokTBuffer:
John Kessenich54ee28f2017-03-11 14:13:00 -07001288 return acceptStruct(type, nodeList);
John Kesseniche6e74942016-06-11 16:43:14 -06001289
1290 case EHTokIdentifier:
1291 // An identifier could be for a user-defined type.
1292 // Note we cache the symbol table lookup, to save for a later rule
1293 // when this is not a type.
John Kessenich854fe242017-03-02 14:30:59 -07001294 token.symbol = parseContext.lookupUserType(*token.string, type);
1295 if (token.symbol != nullptr) {
John Kesseniche6e74942016-06-11 16:43:14 -06001296 advanceToken();
1297 return true;
1298 } else
1299 return false;
1300
John Kessenich71351de2016-06-08 12:50:56 -06001301 case EHTokVoid:
1302 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001303 break;
John Kessenich71351de2016-06-08 12:50:56 -06001304
John Kessenicha1e2d492016-09-20 13:22:58 -06001305 case EHTokString:
1306 new(&type) TType(EbtString);
1307 break;
1308
John Kessenich87142c72016-03-12 20:24:24 -07001309 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001310 new(&type) TType(EbtFloat);
1311 break;
John Kessenich87142c72016-03-12 20:24:24 -07001312 case EHTokFloat1:
1313 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001314 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001315 break;
John Kessenich87142c72016-03-12 20:24:24 -07001316 case EHTokFloat2:
1317 new(&type) TType(EbtFloat, EvqTemporary, 2);
1318 break;
1319 case EHTokFloat3:
1320 new(&type) TType(EbtFloat, EvqTemporary, 3);
1321 break;
1322 case EHTokFloat4:
1323 new(&type) TType(EbtFloat, EvqTemporary, 4);
1324 break;
1325
John Kessenich71351de2016-06-08 12:50:56 -06001326 case EHTokDouble:
1327 new(&type) TType(EbtDouble);
1328 break;
1329 case EHTokDouble1:
1330 new(&type) TType(EbtDouble);
1331 type.makeVector();
1332 break;
1333 case EHTokDouble2:
1334 new(&type) TType(EbtDouble, EvqTemporary, 2);
1335 break;
1336 case EHTokDouble3:
1337 new(&type) TType(EbtDouble, EvqTemporary, 3);
1338 break;
1339 case EHTokDouble4:
1340 new(&type) TType(EbtDouble, EvqTemporary, 4);
1341 break;
1342
1343 case EHTokInt:
1344 case EHTokDword:
1345 new(&type) TType(EbtInt);
1346 break;
1347 case EHTokInt1:
1348 new(&type) TType(EbtInt);
1349 type.makeVector();
1350 break;
John Kessenich87142c72016-03-12 20:24:24 -07001351 case EHTokInt2:
1352 new(&type) TType(EbtInt, EvqTemporary, 2);
1353 break;
1354 case EHTokInt3:
1355 new(&type) TType(EbtInt, EvqTemporary, 3);
1356 break;
1357 case EHTokInt4:
1358 new(&type) TType(EbtInt, EvqTemporary, 4);
1359 break;
1360
John Kessenich71351de2016-06-08 12:50:56 -06001361 case EHTokUint:
1362 new(&type) TType(EbtUint);
1363 break;
1364 case EHTokUint1:
1365 new(&type) TType(EbtUint);
1366 type.makeVector();
1367 break;
1368 case EHTokUint2:
1369 new(&type) TType(EbtUint, EvqTemporary, 2);
1370 break;
1371 case EHTokUint3:
1372 new(&type) TType(EbtUint, EvqTemporary, 3);
1373 break;
1374 case EHTokUint4:
1375 new(&type) TType(EbtUint, EvqTemporary, 4);
1376 break;
1377
1378 case EHTokBool:
1379 new(&type) TType(EbtBool);
1380 break;
1381 case EHTokBool1:
1382 new(&type) TType(EbtBool);
1383 type.makeVector();
1384 break;
John Kessenich87142c72016-03-12 20:24:24 -07001385 case EHTokBool2:
1386 new(&type) TType(EbtBool, EvqTemporary, 2);
1387 break;
1388 case EHTokBool3:
1389 new(&type) TType(EbtBool, EvqTemporary, 3);
1390 break;
1391 case EHTokBool4:
1392 new(&type) TType(EbtBool, EvqTemporary, 4);
1393 break;
1394
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001395 case EHTokHalf:
1396 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1397 break;
1398 case EHTokHalf1:
1399 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1400 type.makeVector();
1401 break;
1402 case EHTokHalf2:
1403 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1404 break;
1405 case EHTokHalf3:
1406 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1407 break;
1408 case EHTokHalf4:
1409 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1410 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001411
steve-lunarg3226b082016-10-26 19:18:55 -06001412 case EHTokMin16float:
1413 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1414 break;
1415 case EHTokMin16float1:
1416 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1417 type.makeVector();
1418 break;
1419 case EHTokMin16float2:
1420 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1421 break;
1422 case EHTokMin16float3:
1423 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1424 break;
1425 case EHTokMin16float4:
1426 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1427 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001428
steve-lunarg3226b082016-10-26 19:18:55 -06001429 case EHTokMin10float:
1430 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1431 break;
1432 case EHTokMin10float1:
1433 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1434 type.makeVector();
1435 break;
1436 case EHTokMin10float2:
1437 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1438 break;
1439 case EHTokMin10float3:
1440 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1441 break;
1442 case EHTokMin10float4:
1443 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1444 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001445
steve-lunarg3226b082016-10-26 19:18:55 -06001446 case EHTokMin16int:
1447 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1448 break;
1449 case EHTokMin16int1:
1450 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1451 type.makeVector();
1452 break;
1453 case EHTokMin16int2:
1454 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1455 break;
1456 case EHTokMin16int3:
1457 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1458 break;
1459 case EHTokMin16int4:
1460 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1461 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001462
steve-lunarg3226b082016-10-26 19:18:55 -06001463 case EHTokMin12int:
1464 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1465 break;
1466 case EHTokMin12int1:
1467 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1468 type.makeVector();
1469 break;
1470 case EHTokMin12int2:
1471 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1472 break;
1473 case EHTokMin12int3:
1474 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1475 break;
1476 case EHTokMin12int4:
1477 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1478 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001479
steve-lunarg3226b082016-10-26 19:18:55 -06001480 case EHTokMin16uint:
1481 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1482 break;
1483 case EHTokMin16uint1:
1484 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1485 type.makeVector();
1486 break;
1487 case EHTokMin16uint2:
1488 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1489 break;
1490 case EHTokMin16uint3:
1491 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1492 break;
1493 case EHTokMin16uint4:
1494 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1495 break;
1496
John Kessenich0133c122016-05-20 12:17:26 -06001497 case EHTokInt1x1:
1498 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1499 break;
1500 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001501 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001502 break;
1503 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001504 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001505 break;
1506 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001507 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001508 break;
1509 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001510 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001511 break;
1512 case EHTokInt2x2:
1513 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1514 break;
1515 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001516 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001517 break;
1518 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001519 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001520 break;
1521 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001522 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001523 break;
1524 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001525 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001526 break;
1527 case EHTokInt3x3:
1528 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1529 break;
1530 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001531 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001532 break;
1533 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001534 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001535 break;
1536 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001537 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001538 break;
1539 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001540 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001541 break;
1542 case EHTokInt4x4:
1543 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1544 break;
1545
John Kessenich71351de2016-06-08 12:50:56 -06001546 case EHTokUint1x1:
1547 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1548 break;
1549 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001550 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001551 break;
1552 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001553 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001554 break;
1555 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001556 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001557 break;
1558 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001559 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001560 break;
1561 case EHTokUint2x2:
1562 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1563 break;
1564 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001565 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001566 break;
1567 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001568 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001569 break;
1570 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001571 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001572 break;
1573 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001574 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001575 break;
1576 case EHTokUint3x3:
1577 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1578 break;
1579 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001580 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001581 break;
1582 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001583 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001584 break;
1585 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001586 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001587 break;
1588 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001589 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001590 break;
1591 case EHTokUint4x4:
1592 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1593 break;
1594
1595 case EHTokBool1x1:
1596 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1597 break;
1598 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001599 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001600 break;
1601 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001602 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001603 break;
1604 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001605 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001606 break;
1607 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001608 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001609 break;
1610 case EHTokBool2x2:
1611 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1612 break;
1613 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001614 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001615 break;
1616 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001617 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001618 break;
1619 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001620 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001621 break;
1622 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001623 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001624 break;
1625 case EHTokBool3x3:
1626 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1627 break;
1628 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001629 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001630 break;
1631 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001632 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001633 break;
1634 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001635 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001636 break;
1637 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001638 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001639 break;
1640 case EHTokBool4x4:
1641 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1642 break;
1643
John Kessenich0133c122016-05-20 12:17:26 -06001644 case EHTokFloat1x1:
1645 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1646 break;
1647 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001648 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001649 break;
1650 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001651 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001652 break;
1653 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001654 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001655 break;
1656 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001657 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001658 break;
John Kessenich87142c72016-03-12 20:24:24 -07001659 case EHTokFloat2x2:
1660 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1661 break;
1662 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001663 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001664 break;
1665 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001666 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001667 break;
John Kessenich0133c122016-05-20 12:17:26 -06001668 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001669 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001670 break;
John Kessenich87142c72016-03-12 20:24:24 -07001671 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001672 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001673 break;
1674 case EHTokFloat3x3:
1675 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1676 break;
1677 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001678 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001679 break;
John Kessenich0133c122016-05-20 12:17:26 -06001680 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001681 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001682 break;
John Kessenich87142c72016-03-12 20:24:24 -07001683 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001684 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001685 break;
1686 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001687 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001688 break;
1689 case EHTokFloat4x4:
1690 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1691 break;
1692
John Kessenich0133c122016-05-20 12:17:26 -06001693 case EHTokDouble1x1:
1694 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1695 break;
1696 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001697 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001698 break;
1699 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001700 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001701 break;
1702 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001703 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001704 break;
1705 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001706 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001707 break;
1708 case EHTokDouble2x2:
1709 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1710 break;
1711 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001712 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001713 break;
1714 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001715 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001716 break;
1717 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001718 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001719 break;
1720 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001721 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001722 break;
1723 case EHTokDouble3x3:
1724 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1725 break;
1726 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001727 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001728 break;
1729 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001730 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001731 break;
1732 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001733 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001734 break;
1735 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001736 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001737 break;
1738 case EHTokDouble4x4:
1739 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1740 break;
1741
John Kessenich87142c72016-03-12 20:24:24 -07001742 default:
1743 return false;
1744 }
1745
1746 advanceToken();
1747
1748 return true;
1749}
1750
John Kesseniche6e74942016-06-11 16:43:14 -06001751// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001752// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1753// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
John Kessenich854fe242017-03-02 14:30:59 -07001754// | struct_type IDENTIFIER // use of previously declared struct type
John Kessenich3d157c52016-07-25 16:05:33 -06001755//
1756// struct_type
1757// : STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001758// | CLASS
John Kessenich3d157c52016-07-25 16:05:33 -06001759// | CBUFFER
1760// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001761//
John Kessenich54ee28f2017-03-11 14:13:00 -07001762bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList)
John Kesseniche6e74942016-06-11 16:43:14 -06001763{
John Kessenichb804de62016-09-05 12:19:18 -06001764 // This storage qualifier will tell us whether it's an AST
1765 // block type or just a generic structure type.
1766 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001767
1768 // CBUFFER
1769 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001770 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001771 // TBUFFER
1772 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001773 storageQualifier = EvqBuffer;
John Kessenich27ffb292017-03-03 17:01:01 -07001774 // CLASS
John Kesseniche6e74942016-06-11 16:43:14 -06001775 // STRUCT
John Kessenich27ffb292017-03-03 17:01:01 -07001776 else if (! acceptTokenClass(EHTokClass) && ! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001777 return false;
1778
1779 // IDENTIFIER
1780 TString structName = "";
1781 if (peekTokenClass(EHTokIdentifier)) {
1782 structName = *token.string;
1783 advanceToken();
1784 }
1785
John Kessenich3d157c52016-07-25 16:05:33 -06001786 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001787 TQualifier postDeclQualifier;
1788 postDeclQualifier.clear();
John Kessenich854fe242017-03-02 14:30:59 -07001789 bool postDeclsFound = acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001790
John Kessenichf3d88bd2017-03-19 12:24:29 -06001791 // LEFT_BRACE, or
John Kessenich854fe242017-03-02 14:30:59 -07001792 // struct_type IDENTIFIER
John Kesseniche6e74942016-06-11 16:43:14 -06001793 if (! acceptTokenClass(EHTokLeftBrace)) {
John Kessenich854fe242017-03-02 14:30:59 -07001794 if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
1795 // struct_type IDENTIFIER
1796 return true;
1797 } else {
1798 expected("{");
1799 return false;
1800 }
John Kesseniche6e74942016-06-11 16:43:14 -06001801 }
1802
John Kessenichf3d88bd2017-03-19 12:24:29 -06001803
John Kesseniche6e74942016-06-11 16:43:14 -06001804 // struct_declaration_list
1805 TTypeList* typeList;
John Kessenichf3d88bd2017-03-19 12:24:29 -06001806 // Save each member function so they can be processed after we have a fully formed 'this'.
1807 TVector<TFunctionDeclarator> functionDeclarators;
1808
1809 parseContext.pushNamespace(structName);
1810 bool acceptedList = acceptStructDeclarationList(typeList, nodeList, structName, functionDeclarators);
1811 parseContext.popNamespace();
1812
1813 if (! acceptedList) {
John Kesseniche6e74942016-06-11 16:43:14 -06001814 expected("struct member declarations");
1815 return false;
1816 }
1817
1818 // RIGHT_BRACE
1819 if (! acceptTokenClass(EHTokRightBrace)) {
1820 expected("}");
1821 return false;
1822 }
1823
1824 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001825 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001826 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001827 else {
John Kessenich7735b942016-09-05 12:40:06 -06001828 postDeclQualifier.storage = storageQualifier;
1829 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001830 }
John Kesseniche6e74942016-06-11 16:43:14 -06001831
John Kessenich727b3742017-02-03 17:57:55 -07001832 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001833
John Kessenich4960baa2017-03-19 18:09:59 -06001834 // For member functions: now that we know the type of 'this', go back and
1835 // - add their implicit argument with 'this' (not to the mangling, just the argument list)
1836 // - parse the functions, their tokens were saved for deferred parsing (now)
1837 for (int b = 0; b < (int)functionDeclarators.size(); ++b) {
1838 // update signature
1839 if (functionDeclarators[b].function->hasImplicitThis())
1840 functionDeclarators[b].function->addThisParameter(type);
1841 }
1842
John Kessenichf3d88bd2017-03-19 12:24:29 -06001843 // All member functions get parsed inside the class/struct namespace and with the
1844 // class/struct members in a symbol-table level.
1845 parseContext.pushNamespace(structName);
1846 bool deferredSuccess = true;
1847 for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) {
1848 // parse body
1849 pushTokenStream(functionDeclarators[b].body);
1850 if (! acceptFunctionBody(functionDeclarators[b], nodeList))
1851 deferredSuccess = false;
1852 popTokenStream();
1853 }
1854 parseContext.popNamespace();
1855
1856 return deferredSuccess;
John Kesseniche6e74942016-06-11 16:43:14 -06001857}
1858
steve-lunarg5da1f032017-02-12 17:50:28 -07001859// struct_buffer
1860// : APPENDSTRUCTUREDBUFFER
1861// | BYTEADDRESSBUFFER
1862// | CONSUMESTRUCTUREDBUFFER
1863// | RWBYTEADDRESSBUFFER
1864// | RWSTRUCTUREDBUFFER
1865// | STRUCTUREDBUFFER
1866bool HlslGrammar::acceptStructBufferType(TType& type)
1867{
1868 const EHlslTokenClass structBuffType = peek();
1869
1870 // TODO: globallycoherent
1871 bool hasTemplateType = true;
1872 bool readonly = false;
1873
1874 TStorageQualifier storage = EvqBuffer;
1875
1876 switch (structBuffType) {
1877 case EHTokAppendStructuredBuffer:
1878 unimplemented("AppendStructuredBuffer");
1879 return false;
1880 case EHTokByteAddressBuffer:
1881 hasTemplateType = false;
1882 readonly = true;
1883 break;
1884 case EHTokConsumeStructuredBuffer:
1885 unimplemented("ConsumeStructuredBuffer");
1886 return false;
1887 case EHTokRWByteAddressBuffer:
1888 hasTemplateType = false;
1889 break;
1890 case EHTokRWStructuredBuffer:
1891 break;
1892 case EHTokStructuredBuffer:
1893 readonly = true;
1894 break;
1895 default:
1896 return false; // not a structure buffer type
1897 }
1898
1899 advanceToken(); // consume the structure keyword
1900
1901 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1902 TType* templateType = new TType;
1903
1904 if (hasTemplateType) {
1905 if (! acceptTokenClass(EHTokLeftAngle)) {
1906 expected("left angle bracket");
1907 return false;
1908 }
1909
1910 if (! acceptType(*templateType)) {
1911 expected("type");
1912 return false;
1913 }
1914 if (! acceptTokenClass(EHTokRightAngle)) {
1915 expected("right angle bracket");
1916 return false;
1917 }
1918 } else {
1919 // byte address buffers have no explicit type.
1920 TType uintType(EbtUint, storage);
1921 templateType->shallowCopy(uintType);
1922 }
1923
1924 // Create an unsized array out of that type.
1925 // TODO: does this work if it's already an array type?
1926 TArraySizes unsizedArray;
1927 unsizedArray.addInnerSize(UnsizedArraySize);
1928 templateType->newArraySizes(unsizedArray);
steve-lunarg40efe5c2017-03-06 12:01:44 -07001929 templateType->getQualifier().storage = storage;
steve-lunargdd8287a2017-02-23 18:04:12 -07001930
1931 // field name is canonical for all structbuffers
1932 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07001933
1934 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07001935
steve-lunarg5da1f032017-02-12 17:50:28 -07001936 TTypeList* blockStruct = new TTypeList;
1937 TTypeLoc member = { templateType, token.loc };
1938 blockStruct->push_back(member);
1939
steve-lunargdd8287a2017-02-23 18:04:12 -07001940 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07001941 TType blockType(blockStruct, "", templateType->getQualifier());
1942
steve-lunargdd8287a2017-02-23 18:04:12 -07001943 blockType.getQualifier().storage = storage;
1944 blockType.getQualifier().readonly = readonly;
1945
1946 // We may have created an equivalent type before, in which case we should use its
1947 // deep structure.
1948 parseContext.shareStructBufferType(blockType);
1949
steve-lunarg5da1f032017-02-12 17:50:28 -07001950 type.shallowCopy(blockType);
1951
1952 return true;
1953}
1954
John Kesseniche6e74942016-06-11 16:43:14 -06001955// struct_declaration_list
1956// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1957//
1958// struct_declaration
1959// : fully_specified_type struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001960// | fully_specified_type IDENTIFIER function_parameters post_decls compound_statement // member-function definition
John Kesseniche6e74942016-06-11 16:43:14 -06001961//
1962// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001963// : IDENTIFIER post_decls
1964// | IDENTIFIER array_specifier post_decls
John Kessenich54ee28f2017-03-11 14:13:00 -07001965// | IDENTIFIER function_parameters post_decls // member-function prototype
John Kesseniche6e74942016-06-11 16:43:14 -06001966//
John Kessenichf3d88bd2017-03-19 12:24:29 -06001967bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*& nodeList, const TString& typeName,
1968 TVector<TFunctionDeclarator>& declarators)
John Kesseniche6e74942016-06-11 16:43:14 -06001969{
1970 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001971 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001972
1973 do {
1974 // success on seeing the RIGHT_BRACE coming up
1975 if (peekTokenClass(EHTokRightBrace))
John Kessenichb16f7e62017-03-11 19:32:47 -07001976 break;
John Kesseniche6e74942016-06-11 16:43:14 -06001977
1978 // struct_declaration
John Kessenich54ee28f2017-03-11 14:13:00 -07001979
1980 bool declarator_list = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001981
1982 // fully_specified_type
1983 TType memberType;
John Kessenich54ee28f2017-03-11 14:13:00 -07001984 if (! acceptFullySpecifiedType(memberType, nodeList)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001985 expected("member type");
1986 return false;
1987 }
1988
1989 // struct_declarator COMMA struct_declarator ...
John Kessenich54ee28f2017-03-11 14:13:00 -07001990 bool functionDefinitionAccepted = false;
John Kesseniche6e74942016-06-11 16:43:14 -06001991 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001992 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001993 expected("member name");
1994 return false;
1995 }
1996
John Kessenich54ee28f2017-03-11 14:13:00 -07001997 if (peekTokenClass(EHTokLeftParen)) {
1998 // function_parameters
1999 if (!declarator_list) {
John Kessenichb16f7e62017-03-11 19:32:47 -07002000 declarators.resize(declarators.size() + 1);
2001 // request a token stream for deferred processing
John Kessenichf3d88bd2017-03-19 12:24:29 -06002002 functionDefinitionAccepted = acceptMemberFunctionDefinition(nodeList, memberType, *idToken.string,
2003 declarators.back());
John Kessenich54ee28f2017-03-11 14:13:00 -07002004 if (functionDefinitionAccepted)
2005 break;
2006 }
2007 expected("member-function definition");
2008 return false;
2009 } else {
2010 // add it to the list of members
2011 TTypeLoc member = { new TType(EbtVoid), token.loc };
2012 member.type->shallowCopy(memberType);
2013 member.type->setFieldName(*idToken.string);
2014 typeList->push_back(member);
John Kesseniche6e74942016-06-11 16:43:14 -06002015
John Kessenich54ee28f2017-03-11 14:13:00 -07002016 // array_specifier
2017 TArraySizes* arraySizes = nullptr;
2018 acceptArraySpecifier(arraySizes);
2019 if (arraySizes)
2020 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06002021
John Kessenich54ee28f2017-03-11 14:13:00 -07002022 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06002023
John Kessenich54ee28f2017-03-11 14:13:00 -07002024 // EQUAL assignment_expression
2025 if (acceptTokenClass(EHTokAssign)) {
2026 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
2027 TIntermTyped* expressionNode = nullptr;
2028 if (! acceptAssignmentExpression(expressionNode)) {
2029 expected("initializer");
2030 return false;
2031 }
John Kessenich18adbdb2017-02-02 15:16:20 -07002032 }
2033 }
John Kesseniche6e74942016-06-11 16:43:14 -06002034 // success on seeing the SEMICOLON coming up
2035 if (peekTokenClass(EHTokSemicolon))
2036 break;
2037
2038 // COMMA
John Kessenich54ee28f2017-03-11 14:13:00 -07002039 if (acceptTokenClass(EHTokComma))
2040 declarator_list = true;
2041 else {
John Kesseniche6e74942016-06-11 16:43:14 -06002042 expected(",");
2043 return false;
2044 }
2045
2046 } while (true);
2047
2048 // SEMI_COLON
John Kessenich54ee28f2017-03-11 14:13:00 -07002049 if (! functionDefinitionAccepted && ! acceptTokenClass(EHTokSemicolon)) {
John Kesseniche6e74942016-06-11 16:43:14 -06002050 expected(";");
2051 return false;
2052 }
2053
2054 } while (true);
John Kessenichb16f7e62017-03-11 19:32:47 -07002055
John Kessenichb16f7e62017-03-11 19:32:47 -07002056 return true;
John Kesseniche6e74942016-06-11 16:43:14 -06002057}
2058
John Kessenich54ee28f2017-03-11 14:13:00 -07002059// member_function_definition
2060// | function_parameters post_decls compound_statement
2061//
2062// Expects type to have EvqGlobal for a static member and
2063// EvqTemporary for non-static member.
John Kessenichf3d88bd2017-03-19 12:24:29 -06002064bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const TType& type, const TString& memberName,
2065 TFunctionDeclarator& declarator)
John Kessenich54ee28f2017-03-11 14:13:00 -07002066{
John Kessenich54ee28f2017-03-11 14:13:00 -07002067 bool accepted = false;
2068
John Kessenichf3d88bd2017-03-19 12:24:29 -06002069 TString* functionName = parseContext.getFullNamespaceName(memberName);
John Kessenich088d52b2017-03-11 17:55:28 -07002070 declarator.function = new TFunction(functionName, type);
John Kessenich4960baa2017-03-19 18:09:59 -06002071 if (type.getQualifier().storage == EvqTemporary)
2072 declarator.function->setImplicitThis();
John Kessenich54ee28f2017-03-11 14:13:00 -07002073
2074 // function_parameters
John Kessenich088d52b2017-03-11 17:55:28 -07002075 if (acceptFunctionParameters(*declarator.function)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002076 // post_decls
John Kessenich088d52b2017-03-11 17:55:28 -07002077 acceptPostDecls(declarator.function->getWritableType().getQualifier());
John Kessenich54ee28f2017-03-11 14:13:00 -07002078
2079 // compound_statement (function body definition)
2080 if (peekTokenClass(EHTokLeftBrace)) {
John Kessenich088d52b2017-03-11 17:55:28 -07002081 declarator.loc = token.loc;
John Kessenichf3d88bd2017-03-19 12:24:29 -06002082 declarator.body = new TVector<HlslToken>;
2083 accepted = acceptFunctionDefinition(declarator, nodeList, declarator.body);
John Kessenich54ee28f2017-03-11 14:13:00 -07002084 }
2085 } else
2086 expected("function parameter list");
2087
John Kessenich54ee28f2017-03-11 14:13:00 -07002088 return accepted;
2089}
2090
John Kessenich5f934b02016-03-13 17:58:25 -06002091// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06002092// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06002093// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002094//
2095bool HlslGrammar::acceptFunctionParameters(TFunction& function)
2096{
John Kessenich078d7f22016-03-14 10:02:11 -06002097 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002098 if (! acceptTokenClass(EHTokLeftParen))
2099 return false;
2100
John Kessenich71351de2016-06-08 12:50:56 -06002101 // VOID RIGHT_PAREN
2102 if (! acceptTokenClass(EHTokVoid)) {
2103 do {
2104 // parameter_declaration
2105 if (! acceptParameterDeclaration(function))
2106 break;
John Kessenich5f934b02016-03-13 17:58:25 -06002107
John Kessenich71351de2016-06-08 12:50:56 -06002108 // COMMA
2109 if (! acceptTokenClass(EHTokComma))
2110 break;
2111 } while (true);
2112 }
John Kessenich5f934b02016-03-13 17:58:25 -06002113
John Kessenich078d7f22016-03-14 10:02:11 -06002114 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06002115 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002116 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002117 return false;
2118 }
2119
2120 return true;
2121}
2122
steve-lunarg26d31452016-12-23 18:56:57 -07002123// default_parameter_declaration
2124// : EQUAL conditional_expression
2125// : EQUAL initializer
2126bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2127{
2128 node = nullptr;
2129
2130 // Valid not to have a default_parameter_declaration
2131 if (!acceptTokenClass(EHTokAssign))
2132 return true;
2133
2134 if (!acceptConditionalExpression(node)) {
2135 if (!acceptInitializer(node))
2136 return false;
2137
2138 // For initializer lists, we have to const-fold into a constructor for the type, so build
2139 // that.
2140 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2141 if (constructor == nullptr) // cannot construct
2142 return false;
2143
2144 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002145 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002146 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002147
steve-lunarg26d31452016-12-23 18:56:57 -07002148 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2149 }
2150
2151 // If this is simply a constant, we can use it directly.
2152 if (node->getAsConstantUnion())
2153 return true;
2154
2155 // Otherwise, it has to be const-foldable.
2156 TIntermTyped* origNode = node;
2157
2158 node = intermediate.fold(node->getAsAggregate());
2159
2160 if (node != nullptr && origNode != node)
2161 return true;
2162
2163 parseContext.error(token.loc, "invalid default parameter value", "", "");
2164
2165 return false;
2166}
2167
John Kessenich5f934b02016-03-13 17:58:25 -06002168// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002169// : fully_specified_type post_decls [ = default_parameter_declaration ]
2170// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002171//
2172bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2173{
2174 // fully_specified_type
2175 TType* type = new TType;
2176 if (! acceptFullySpecifiedType(*type))
2177 return false;
2178
2179 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002180 HlslToken idToken;
2181 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002182
John Kessenich19b92ff2016-06-19 11:50:34 -06002183 // array_specifier
2184 TArraySizes* arraySizes = nullptr;
2185 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002186 if (arraySizes) {
2187 if (arraySizes->isImplicit()) {
2188 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2189 return false;
2190 }
2191
John Kessenich19b92ff2016-06-19 11:50:34 -06002192 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002193 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002194
2195 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002196 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002197
steve-lunarg26d31452016-12-23 18:56:57 -07002198 TIntermTyped* defaultValue;
2199 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2200 return false;
2201
John Kessenich5aa59e22016-06-17 15:50:47 -06002202 parseContext.paramFix(*type);
2203
steve-lunarg26d31452016-12-23 18:56:57 -07002204 // If any prior parameters have default values, all the parameters after that must as well.
2205 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2206 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2207 return false;
2208 }
2209
2210 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002211 function.addParameter(param);
2212
2213 return true;
2214}
2215
2216// Do the work to create the function definition in addition to
2217// parsing the body (compound_statement).
John Kessenichb16f7e62017-03-11 19:32:47 -07002218//
2219// If 'deferredTokens' are passed in, just get the token stream,
2220// don't process.
2221//
2222bool HlslGrammar::acceptFunctionDefinition(TFunctionDeclarator& declarator, TIntermNode*& nodeList,
2223 TVector<HlslToken>* deferredTokens)
John Kessenich5f934b02016-03-13 17:58:25 -06002224{
John Kessenich088d52b2017-03-11 17:55:28 -07002225 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, false /* not prototype */);
John Kessenich5f934b02016-03-13 17:58:25 -06002226
John Kessenichb16f7e62017-03-11 19:32:47 -07002227 if (deferredTokens)
2228 return captureBlockTokens(*deferredTokens);
2229 else
John Kessenich4960baa2017-03-19 18:09:59 -06002230 return acceptFunctionBody(declarator, nodeList);
John Kessenich088d52b2017-03-11 17:55:28 -07002231}
2232
2233bool HlslGrammar::acceptFunctionBody(TFunctionDeclarator& declarator, TIntermNode*& nodeList)
2234{
2235 // we might get back an entry-point
John Kessenichca71d942017-03-07 20:44:09 -07002236 TIntermNode* entryPointNode = nullptr;
2237
John Kessenich077e0522016-06-09 02:02:17 -06002238 // This does a pushScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002239 TIntermNode* functionNode = parseContext.handleFunctionDefinition(declarator.loc, *declarator.function,
2240 declarator.attributes, entryPointNode);
John Kessenich5f934b02016-03-13 17:58:25 -06002241
2242 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002243 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002244 if (! acceptCompoundStatement(functionBody))
2245 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002246
John Kessenich54ee28f2017-03-11 14:13:00 -07002247 // this does a popScope()
John Kessenich088d52b2017-03-11 17:55:28 -07002248 parseContext.handleFunctionBody(declarator.loc, *declarator.function, functionBody, functionNode);
John Kessenichca71d942017-03-07 20:44:09 -07002249
2250 // Hook up the 1 or 2 function definitions.
2251 nodeList = intermediate.growAggregate(nodeList, functionNode);
2252 nodeList = intermediate.growAggregate(nodeList, entryPointNode);
John Kessenich02467d82017-01-19 15:41:47 -07002253
2254 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002255}
2256
John Kessenich0d2b6de2016-06-05 11:23:11 -06002257// Accept an expression with parenthesis around it, where
2258// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002259// syntactically required ones like in "if ( expression )".
2260//
2261// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002262//
2263// Note this one is not set up to be speculative; as it gives
2264// errors if not found.
2265//
2266bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2267{
2268 // LEFT_PAREN
2269 if (! acceptTokenClass(EHTokLeftParen))
2270 expected("(");
2271
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002272 bool decl = false;
2273 TIntermNode* declNode = nullptr;
2274 decl = acceptControlDeclaration(declNode);
2275 if (decl) {
2276 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2277 expected("initialized declaration");
2278 return false;
2279 } else
2280 expression = declNode->getAsTyped();
2281 } else {
2282 // no declaration
2283 if (! acceptExpression(expression)) {
2284 expected("expression");
2285 return false;
2286 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002287 }
2288
2289 // RIGHT_PAREN
2290 if (! acceptTokenClass(EHTokRightParen))
2291 expected(")");
2292
2293 return true;
2294}
2295
John Kessenich34fb0362016-05-03 23:17:20 -06002296// The top-level full expression recognizer.
2297//
John Kessenich87142c72016-03-12 20:24:24 -07002298// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002299// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002300//
2301bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2302{
LoopDawgef764a22016-06-03 09:17:51 -06002303 node = nullptr;
2304
John Kessenich34fb0362016-05-03 23:17:20 -06002305 // assignment_expression
2306 if (! acceptAssignmentExpression(node))
2307 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002308
John Kessenich34fb0362016-05-03 23:17:20 -06002309 if (! peekTokenClass(EHTokComma))
2310 return true;
2311
2312 do {
2313 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002314 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002315 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002316
John Kessenich34fb0362016-05-03 23:17:20 -06002317 // ... assignment_expression
2318 TIntermTyped* rightNode = nullptr;
2319 if (! acceptAssignmentExpression(rightNode)) {
2320 expected("assignment expression");
2321 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002322 }
2323
John Kessenich34fb0362016-05-03 23:17:20 -06002324 node = intermediate.addComma(node, rightNode, loc);
2325
2326 if (! peekTokenClass(EHTokComma))
2327 return true;
2328 } while (true);
2329}
2330
John Kessenich07354242016-07-01 19:58:06 -06002331// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002332// : LEFT_BRACE RIGHT_BRACE
2333// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002334//
2335// initializer_list
2336// : assignment_expression COMMA assignment_expression COMMA ...
2337//
2338bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2339{
2340 // LEFT_BRACE
2341 if (! acceptTokenClass(EHTokLeftBrace))
2342 return false;
2343
John Kessenich98ad4852016-11-27 17:39:07 -07002344 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002345 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002346 if (acceptTokenClass(EHTokRightBrace)) {
2347 // a zero-length initializer list
2348 node = intermediate.makeAggregate(loc);
2349 return true;
2350 }
2351
2352 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002353 node = nullptr;
2354 do {
2355 // assignment_expression
2356 TIntermTyped* expr;
2357 if (! acceptAssignmentExpression(expr)) {
2358 expected("assignment expression in initializer list");
2359 return false;
2360 }
2361 node = intermediate.growAggregate(node, expr, loc);
2362
2363 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002364 if (acceptTokenClass(EHTokComma)) {
2365 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2366 return true;
John Kessenich07354242016-07-01 19:58:06 -06002367 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002368 }
John Kessenich07354242016-07-01 19:58:06 -06002369
2370 // RIGHT_BRACE
2371 if (acceptTokenClass(EHTokRightBrace))
2372 return true;
2373
2374 expected(", or }");
2375 return false;
2376 } while (true);
2377}
2378
John Kessenich34fb0362016-05-03 23:17:20 -06002379// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002380// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002381//
2382// a op (b op (c op d))
2383//
2384// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002385// : initializer
2386// | conditional_expression
2387// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002388//
2389bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2390{
John Kessenich07354242016-07-01 19:58:06 -06002391 // initializer
2392 if (peekTokenClass(EHTokLeftBrace)) {
2393 if (acceptInitializer(node))
2394 return true;
2395
2396 expected("initializer");
2397 return false;
2398 }
2399
John Kessenich00957f82016-07-27 10:39:57 -06002400 // conditional_expression
2401 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002402 return false;
2403
John Kessenich07354242016-07-01 19:58:06 -06002404 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002405 TOperator assignOp = HlslOpMap::assignment(peek());
2406 if (assignOp == EOpNull)
2407 return true;
2408
John Kessenich00957f82016-07-27 10:39:57 -06002409 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002410 TSourceLoc loc = token.loc;
2411 advanceToken();
2412
John Kessenich00957f82016-07-27 10:39:57 -06002413 // conditional_expression assign_op conditional_expression ...
2414 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002415 // gets the right-to-left associativity.
2416 TIntermTyped* rightNode = nullptr;
2417 if (! acceptAssignmentExpression(rightNode)) {
2418 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002419 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002420 }
2421
John Kessenichd21baed2016-09-16 03:05:12 -06002422 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002423 node = parseContext.handleLvalue(loc, "assign", node);
2424
John Kessenichfea226b2016-07-28 17:53:56 -06002425 if (node == nullptr) {
2426 parseContext.error(loc, "could not create assignment", "", "");
2427 return false;
2428 }
John Kessenich34fb0362016-05-03 23:17:20 -06002429
2430 if (! peekTokenClass(EHTokComma))
2431 return true;
2432
2433 return true;
2434}
2435
John Kessenich00957f82016-07-27 10:39:57 -06002436// Accept a conditional expression, which associates right-to-left,
2437// accomplished by the "true" expression calling down to lower
2438// precedence levels than this level.
2439//
2440// conditional_expression
2441// : binary_expression
2442// | binary_expression QUESTION expression COLON assignment_expression
2443//
2444bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2445{
2446 // binary_expression
2447 if (! acceptBinaryExpression(node, PlLogicalOr))
2448 return false;
2449
2450 if (! acceptTokenClass(EHTokQuestion))
2451 return true;
2452
2453 TIntermTyped* trueNode = nullptr;
2454 if (! acceptExpression(trueNode)) {
2455 expected("expression after ?");
2456 return false;
2457 }
2458 TSourceLoc loc = token.loc;
2459
2460 if (! acceptTokenClass(EHTokColon)) {
2461 expected(":");
2462 return false;
2463 }
2464
2465 TIntermTyped* falseNode = nullptr;
2466 if (! acceptAssignmentExpression(falseNode)) {
2467 expected("expression after :");
2468 return false;
2469 }
2470
2471 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2472
2473 return true;
2474}
2475
John Kessenich34fb0362016-05-03 23:17:20 -06002476// Accept a binary expression, for binary operations that
2477// associate left-to-right. This is, it is implicit, for example
2478//
2479// ((a op b) op c) op d
2480//
2481// binary_expression
2482// : expression op expression op expression ...
2483//
2484// where 'expression' is the next higher level in precedence.
2485//
2486bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2487{
2488 if (precedenceLevel > PlMul)
2489 return acceptUnaryExpression(node);
2490
2491 // assignment_expression
2492 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2493 return false;
2494
John Kessenich34fb0362016-05-03 23:17:20 -06002495 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002496 TOperator op = HlslOpMap::binary(peek());
2497 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2498 if (tokenLevel < precedenceLevel)
2499 return true;
2500
John Kessenich34fb0362016-05-03 23:17:20 -06002501 // ... op
2502 TSourceLoc loc = token.loc;
2503 advanceToken();
2504
2505 // ... expression
2506 TIntermTyped* rightNode = nullptr;
2507 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2508 expected("expression");
2509 return false;
2510 }
2511
2512 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002513 if (node == nullptr) {
2514 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2515 return false;
2516 }
John Kessenich34fb0362016-05-03 23:17:20 -06002517 } while (true);
2518}
2519
2520// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002521// : (type) unary_expression
2522// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002523// | - unary_expression
2524// | ! unary_expression
2525// | ~ unary_expression
2526// | ++ unary_expression
2527// | -- unary_expression
2528// | postfix_expression
2529//
2530bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2531{
John Kessenich1cc1a282016-06-03 16:55:49 -06002532 // (type) unary_expression
2533 // Have to look two steps ahead, because this could be, e.g., a
2534 // postfix_expression instead, since that also starts with at "(".
2535 if (acceptTokenClass(EHTokLeftParen)) {
2536 TType castType;
2537 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002538 if (acceptTokenClass(EHTokRightParen)) {
2539 // We've matched "(type)" now, get the expression to cast
2540 TSourceLoc loc = token.loc;
2541 if (! acceptUnaryExpression(node))
2542 return false;
2543
2544 // Hook it up like a constructor
2545 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2546 if (constructorFunction == nullptr) {
2547 expected("type that can be constructed");
2548 return false;
2549 }
2550 TIntermTyped* arguments = nullptr;
2551 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2552 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2553
2554 return true;
2555 } else {
2556 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2557 // the '(int' part. We must back up twice.
2558 recedeToken();
2559 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002560 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002561 } else {
2562 // This isn't a type cast, but it still started "(", so if it is a
2563 // unary expression, it can only be a postfix_expression, so try that.
2564 // Back it up first.
2565 recedeToken();
2566 return acceptPostfixExpression(node);
2567 }
2568 }
2569
2570 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002571 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002572
John Kessenich1cc1a282016-06-03 16:55:49 -06002573 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002574 if (unaryOp == EOpNull)
2575 return acceptPostfixExpression(node);
2576
2577 // op unary_expression
2578 TSourceLoc loc = token.loc;
2579 advanceToken();
2580 if (! acceptUnaryExpression(node))
2581 return false;
2582
2583 // + is a no-op
2584 if (unaryOp == EOpAdd)
2585 return true;
2586
2587 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002588
2589 // These unary ops require lvalues
2590 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2591 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002592
2593 return node != nullptr;
2594}
2595
2596// postfix_expression
2597// : LEFT_PAREN expression RIGHT_PAREN
2598// | literal
2599// | constructor
2600// | identifier
2601// | function_call
2602// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2603// | postfix_expression DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002604// | postfix_expression DOT IDENTIFIER arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002605// | postfix_expression COLONCOLON IDENTIFIER arguments
John Kessenich34fb0362016-05-03 23:17:20 -06002606// | postfix_expression INC_OP
2607// | postfix_expression DEC_OP
2608//
2609bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2610{
2611 // Not implemented as self-recursive:
John Kessenich54ee28f2017-03-11 14:13:00 -07002612 // The logical "right recursion" is done with a loop at the end
John Kessenich34fb0362016-05-03 23:17:20 -06002613
2614 // idToken will pick up either a variable or a function name in a function call
2615 HlslToken idToken;
2616
John Kessenich54ee28f2017-03-11 14:13:00 -07002617 // scopeBase will pick up the type symbol on the left of '::'
John Kessenich4960baa2017-03-19 18:09:59 -06002618 TSymbol* scope = nullptr;
John Kessenich54ee28f2017-03-11 14:13:00 -07002619
John Kessenich21472ae2016-06-04 11:46:33 -06002620 // Find something before the postfix operations, as they can't operate
2621 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002622 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002623 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002624 if (! acceptExpression(node)) {
2625 expected("expression");
2626 return false;
2627 }
2628 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002629 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002630 return false;
2631 }
John Kessenich34fb0362016-05-03 23:17:20 -06002632 } else if (acceptLiteral(node)) {
John Kessenichecba76f2017-01-06 00:34:48 -07002633 // literal (nothing else to do yet), go on to the
John Kessenich34fb0362016-05-03 23:17:20 -06002634 } else if (acceptConstructor(node)) {
2635 // constructor (nothing else to do yet)
2636 } else if (acceptIdentifier(idToken)) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002637 // user-type, identifier, or function name
2638 if (peekTokenClass(EHTokColonColon)) {
2639 TType type;
John Kessenich4960baa2017-03-19 18:09:59 -06002640 scope = parseContext.lookupUserType(*idToken.string, type);
2641 if (scope == nullptr) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002642 expected("type left of ::");
2643 return false;
2644 }
2645 } else if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002646 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002647 } else if (acceptFunctionCall(idToken, node)) {
2648 // function_call (nothing else to do yet)
2649 } else {
2650 expected("function call arguments");
2651 return false;
2652 }
John Kessenich21472ae2016-06-04 11:46:33 -06002653 } else {
2654 // nothing found, can't post operate
2655 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002656 }
2657
steve-lunarga2b01a02016-11-28 17:09:54 -07002658 // This is to guarantee we do this no matter how we get out of the stack frame.
2659 // This way there's no bug if an early return forgets to do it.
2660 struct tFinalize {
2661 tFinalize(HlslParseContext& p) : parseContext(p) { }
2662 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002663 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002664 private:
John Kessenichca71d942017-03-07 20:44:09 -07002665 const tFinalize& operator=(const tFinalize&) { return *this; }
John Kessenichefeefd92017-03-01 13:12:26 -07002666 tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
steve-lunarga2b01a02016-11-28 17:09:54 -07002667 } finalize(parseContext);
2668
2669 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2670 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2671 // level: hence the init and finalize. Even though in practice these must be
2672 // constants, they are parsed no matter what.
2673 parseContext.initFlattening();
2674
John Kessenich21472ae2016-06-04 11:46:33 -06002675 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002676 do {
2677 TSourceLoc loc = token.loc;
2678 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002679
John Kessenich34fb0362016-05-03 23:17:20 -06002680 // Consume only a valid post-unary operator, otherwise we are done.
2681 switch (postOp) {
2682 case EOpIndexDirectStruct:
2683 case EOpIndexIndirect:
2684 case EOpPostIncrement:
2685 case EOpPostDecrement:
John Kessenich54ee28f2017-03-11 14:13:00 -07002686 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002687 advanceToken();
2688 break;
2689 default:
2690 return true;
2691 }
John Kessenich87142c72016-03-12 20:24:24 -07002692
John Kessenich34fb0362016-05-03 23:17:20 -06002693 // We have a valid post-unary operator, process it.
2694 switch (postOp) {
John Kessenich54ee28f2017-03-11 14:13:00 -07002695 case EOpScoping:
John Kessenich34fb0362016-05-03 23:17:20 -06002696 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002697 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002698 // DOT IDENTIFIER
John Kessenich516d92d2017-03-08 20:09:03 -07002699 // includes swizzles, member variables, and member functions
John Kessenich93a162a2016-06-17 17:16:27 -06002700 HlslToken field;
2701 if (! acceptIdentifier(field)) {
2702 expected("swizzle or member");
2703 return false;
2704 }
LoopDawg4886f692016-06-29 10:58:58 -06002705
John Kessenich516d92d2017-03-08 20:09:03 -07002706 if (peekTokenClass(EHTokLeftParen)) {
2707 // member function
2708 TIntermTyped* thisNode = node;
LoopDawg4886f692016-06-29 10:58:58 -06002709
John Kessenich516d92d2017-03-08 20:09:03 -07002710 // arguments
John Kessenich4960baa2017-03-19 18:09:59 -06002711 if (! acceptFunctionCall(field, node, thisNode, scope)) {
LoopDawg4886f692016-06-29 10:58:58 -06002712 expected("function parameters");
2713 return false;
2714 }
John Kessenich516d92d2017-03-08 20:09:03 -07002715 } else
2716 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002717
John Kessenich34fb0362016-05-03 23:17:20 -06002718 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002719 }
John Kessenich34fb0362016-05-03 23:17:20 -06002720 case EOpIndexIndirect:
2721 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002722 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002723 TIntermTyped* indexNode = nullptr;
2724 if (! acceptExpression(indexNode) ||
2725 ! peekTokenClass(EHTokRightBracket)) {
2726 expected("expression followed by ']'");
2727 return false;
2728 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002729 advanceToken();
2730 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2731 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002732 }
2733 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002734 // INC_OP
2735 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002736 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002737 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002738 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002739 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002740 break;
2741 default:
2742 assert(0);
2743 break;
2744 }
2745 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002746}
2747
John Kessenichd016be12016-03-13 11:24:20 -06002748// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002749// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002750//
2751bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2752{
2753 // type
2754 TType type;
2755 if (acceptType(type)) {
2756 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2757 if (constructorFunction == nullptr)
2758 return false;
2759
2760 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002761 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002762 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002763 // It's possible this is a type keyword used as an identifier. Put the token back
2764 // for later use.
2765 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002766 return false;
2767 }
2768
2769 // hook it up
2770 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2771
2772 return true;
2773 }
2774
2775 return false;
2776}
2777
John Kessenich34fb0362016-05-03 23:17:20 -06002778// The function_call identifier was already recognized, and passed in as idToken.
2779//
2780// function_call
2781// : [idToken] arguments
2782//
John Kessenich54ee28f2017-03-11 14:13:00 -07002783bool HlslGrammar::acceptFunctionCall(HlslToken callToken, TIntermTyped*& node, TIntermTyped* baseObject,
John Kessenich4960baa2017-03-19 18:09:59 -06002784 const TSymbol* scope)
John Kessenich34fb0362016-05-03 23:17:20 -06002785{
John Kessenich54ee28f2017-03-11 14:13:00 -07002786 // name
2787 TString* functionName = nullptr;
John Kessenich4960baa2017-03-19 18:09:59 -06002788 if ((baseObject == nullptr && scope == nullptr) ||
2789 parseContext.isBuiltInMethod(callToken.loc, baseObject, *callToken.string)) {
2790 // Built-in methods are not in the symbol table as methods, but as global functions
2791 // taking an explicit 'this' as the first argument.
John Kessenich54ee28f2017-03-11 14:13:00 -07002792 functionName = callToken.string;
John Kessenich4960baa2017-03-19 18:09:59 -06002793 } else {
John Kessenich54ee28f2017-03-11 14:13:00 -07002794 functionName = NewPoolTString("");
John Kessenich4960baa2017-03-19 18:09:59 -06002795 if (baseObject != nullptr)
2796 functionName->append(baseObject->getType().getTypeName());
2797 else if (scope != nullptr)
2798 functionName->append(scope->getType().getTypeName());
John Kessenichf3d88bd2017-03-19 12:24:29 -06002799 parseContext.addScopeMangler(*functionName);
John Kessenich54ee28f2017-03-11 14:13:00 -07002800 functionName->append(*callToken.string);
John Kessenich5f12d2f2017-03-11 09:39:55 -07002801 }
LoopDawg4886f692016-06-29 10:58:58 -06002802
John Kessenich54ee28f2017-03-11 14:13:00 -07002803 // function
2804 TFunction* function = new TFunction(functionName, TType(EbtVoid));
2805
2806 // arguments
John Kessenich54ee28f2017-03-11 14:13:00 -07002807 TIntermTyped* arguments = nullptr;
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002808 if (baseObject != nullptr) {
2809 // Non-static member functions have an implicit first argument of the base object.
John Kessenich54ee28f2017-03-11 14:13:00 -07002810 parseContext.handleFunctionArgument(function, arguments, baseObject);
John Kessenichdfbdd9e2017-03-19 13:10:28 -06002811 }
John Kessenich4678ca92016-05-13 09:33:42 -06002812 if (! acceptArguments(function, arguments))
2813 return false;
2814
John Kessenich54ee28f2017-03-11 14:13:00 -07002815 // call
John Kessenich5f12d2f2017-03-11 09:39:55 -07002816 node = parseContext.handleFunctionCall(callToken.loc, function, arguments);
John Kessenich4678ca92016-05-13 09:33:42 -06002817
2818 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002819}
2820
John Kessenich87142c72016-03-12 20:24:24 -07002821// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002822// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002823//
John Kessenichd016be12016-03-13 11:24:20 -06002824// The arguments are pushed onto the 'function' argument list and
2825// onto the 'arguments' aggregate.
2826//
John Kessenich4678ca92016-05-13 09:33:42 -06002827bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002828{
John Kessenich078d7f22016-03-14 10:02:11 -06002829 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002830 if (! acceptTokenClass(EHTokLeftParen))
2831 return false;
2832
2833 do {
John Kessenichd016be12016-03-13 11:24:20 -06002834 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002835 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002836 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002837 break;
John Kessenichd016be12016-03-13 11:24:20 -06002838
2839 // hook it up
2840 parseContext.handleFunctionArgument(function, arguments, arg);
2841
John Kessenich078d7f22016-03-14 10:02:11 -06002842 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002843 if (! acceptTokenClass(EHTokComma))
2844 break;
2845 } while (true);
2846
John Kessenich078d7f22016-03-14 10:02:11 -06002847 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002848 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002849 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002850 return false;
2851 }
2852
2853 return true;
2854}
2855
2856bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2857{
2858 switch (token.tokenClass) {
2859 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002860 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002861 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002862 case EHTokUintConstant:
2863 node = intermediate.addConstantUnion(token.u, token.loc, true);
2864 break;
John Kessenich87142c72016-03-12 20:24:24 -07002865 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002866 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002867 break;
2868 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002869 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002870 break;
2871 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002872 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002873 break;
John Kessenich86f71382016-09-19 20:23:18 -06002874 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002875 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002876 break;
John Kessenich87142c72016-03-12 20:24:24 -07002877
2878 default:
2879 return false;
2880 }
2881
2882 advanceToken();
2883
2884 return true;
2885}
2886
John Kessenich5f934b02016-03-13 17:58:25 -06002887// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002888// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002889//
John Kessenich21472ae2016-06-04 11:46:33 -06002890bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002891{
John Kessenich21472ae2016-06-04 11:46:33 -06002892 TIntermAggregate* compoundStatement = nullptr;
2893
John Kessenich34fb0362016-05-03 23:17:20 -06002894 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002895 if (! acceptTokenClass(EHTokLeftBrace))
2896 return false;
2897
2898 // statement statement ...
2899 TIntermNode* statement = nullptr;
2900 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002901 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2902 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2903 branch->getFlowOp() == EOpDefault)) {
2904 // hook up individual subsequences within a switch statement
2905 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2906 compoundStatement = nullptr;
2907 } else {
2908 // hook it up to the growing compound statement
2909 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2910 }
John Kessenich5f934b02016-03-13 17:58:25 -06002911 }
John Kessenich34fb0362016-05-03 23:17:20 -06002912 if (compoundStatement)
2913 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002914
John Kessenich21472ae2016-06-04 11:46:33 -06002915 retStatement = compoundStatement;
2916
John Kessenich34fb0362016-05-03 23:17:20 -06002917 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002918 return acceptTokenClass(EHTokRightBrace);
2919}
2920
John Kessenich0d2b6de2016-06-05 11:23:11 -06002921bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2922{
2923 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002924 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002925 parseContext.popScope();
2926
2927 return result;
2928}
2929
John Kessenich077e0522016-06-09 02:02:17 -06002930bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002931{
John Kessenich077e0522016-06-09 02:02:17 -06002932 parseContext.pushScope();
2933 bool result = acceptCompoundStatement(statement);
2934 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002935
2936 return result;
2937}
2938
John Kessenich5f934b02016-03-13 17:58:25 -06002939// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002940// : attributes attributed_statement
2941//
2942// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002943// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002944// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002945// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002946// | declaration_statement
2947// | selection_statement
2948// | switch_statement
2949// | case_label
2950// | iteration_statement
2951// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002952//
2953bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2954{
John Kessenich21472ae2016-06-04 11:46:33 -06002955 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002956
John Kessenich21472ae2016-06-04 11:46:33 -06002957 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002958 TAttributeMap attributes;
2959 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002960
John Kessenich21472ae2016-06-04 11:46:33 -06002961 // attributed_statement
2962 switch (peek()) {
2963 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002964 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002965
John Kessenich21472ae2016-06-04 11:46:33 -06002966 case EHTokIf:
2967 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002968
John Kessenich21472ae2016-06-04 11:46:33 -06002969 case EHTokSwitch:
2970 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002971
John Kessenich21472ae2016-06-04 11:46:33 -06002972 case EHTokFor:
2973 case EHTokDo:
2974 case EHTokWhile:
2975 return acceptIterationStatement(statement);
2976
2977 case EHTokContinue:
2978 case EHTokBreak:
2979 case EHTokDiscard:
2980 case EHTokReturn:
2981 return acceptJumpStatement(statement);
2982
2983 case EHTokCase:
2984 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002985 case EHTokDefault:
2986 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002987
2988 case EHTokSemicolon:
2989 return acceptTokenClass(EHTokSemicolon);
2990
2991 case EHTokRightBrace:
2992 // Performance: not strictly necessary, but stops a bunch of hunting early,
2993 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002994 return false;
2995
John Kessenich21472ae2016-06-04 11:46:33 -06002996 default:
2997 {
2998 // declaration
2999 if (acceptDeclaration(statement))
3000 return true;
3001
3002 // expression
3003 TIntermTyped* node;
3004 if (acceptExpression(node))
3005 statement = node;
3006 else
3007 return false;
3008
3009 // SEMICOLON (following an expression)
3010 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06003011 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06003012 return false;
3013 }
3014 }
3015 }
3016
John Kessenich5f934b02016-03-13 17:58:25 -06003017 return true;
John Kessenich87142c72016-03-12 20:24:24 -07003018}
3019
John Kessenich21472ae2016-06-04 11:46:33 -06003020// attributes
3021// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
3022//
3023// attribute:
3024// : UNROLL
3025// | UNROLL LEFT_PAREN literal RIGHT_PAREN
3026// | FASTOPT
3027// | ALLOW_UAV_CONDITION
3028// | BRANCH
3029// | FLATTEN
3030// | FORCECASE
3031// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06003032// | DOMAIN
3033// | EARLYDEPTHSTENCIL
3034// | INSTANCE
3035// | MAXTESSFACTOR
3036// | OUTPUTCONTROLPOINTS
3037// | OUTPUTTOPOLOGY
3038// | PARTITIONING
3039// | PATCHCONSTANTFUNC
3040// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06003041//
steve-lunarg1868b142016-10-20 13:07:10 -06003042void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06003043{
steve-lunarg1868b142016-10-20 13:07:10 -06003044 // For now, accept the [ XXX(X) ] syntax, but drop all but
3045 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06003046 // TODO: subset to correct set? Pass on?
3047 do {
steve-lunarg1868b142016-10-20 13:07:10 -06003048 HlslToken idToken;
3049
John Kessenich0d2b6de2016-06-05 11:23:11 -06003050 // LEFT_BRACKET?
3051 if (! acceptTokenClass(EHTokLeftBracket))
3052 return;
3053
3054 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06003055 if (acceptIdentifier(idToken)) {
3056 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06003057 } else if (! peekTokenClass(EHTokRightBracket)) {
3058 expected("identifier");
3059 advanceToken();
3060 }
3061
steve-lunarga22f7db2016-11-11 08:17:44 -07003062 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06003063
3064 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06003065 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07003066 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06003067
John Kessenich0d2b6de2016-06-05 11:23:11 -06003068 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07003069 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07003070
steve-lunarga22f7db2016-11-11 08:17:44 -07003071 while (acceptAssignmentExpression(node)) {
3072 expectingExpression = false;
3073 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06003074 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07003075 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06003076 }
3077
steve-lunarga22f7db2016-11-11 08:17:44 -07003078 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06003079 if (! acceptTokenClass(EHTokRightParen))
3080 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07003081
3082 // Error for partial or missing expression
3083 if (expectingExpression || expressions->getSequence().empty())
3084 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06003085 }
3086
3087 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06003088 if (!acceptTokenClass(EHTokRightBracket)) {
3089 expected("]");
3090 return;
3091 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06003092
steve-lunarg1868b142016-10-20 13:07:10 -06003093 // Add any values we found into the attribute map. This accepts
3094 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07003095 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06003096 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06003097}
3098
John Kessenich0d2b6de2016-06-05 11:23:11 -06003099// selection_statement
3100// : IF LEFT_PAREN expression RIGHT_PAREN statement
3101// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
3102//
John Kessenich21472ae2016-06-04 11:46:33 -06003103bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
3104{
John Kessenich0d2b6de2016-06-05 11:23:11 -06003105 TSourceLoc loc = token.loc;
3106
3107 // IF
3108 if (! acceptTokenClass(EHTokIf))
3109 return false;
3110
3111 // so that something declared in the condition is scoped to the lifetimes
3112 // of the then-else statements
3113 parseContext.pushScope();
3114
3115 // LEFT_PAREN expression RIGHT_PAREN
3116 TIntermTyped* condition;
3117 if (! acceptParenExpression(condition))
3118 return false;
3119
3120 // create the child statements
3121 TIntermNodePair thenElse = { nullptr, nullptr };
3122
3123 // then statement
3124 if (! acceptScopedStatement(thenElse.node1)) {
3125 expected("then statement");
3126 return false;
3127 }
3128
3129 // ELSE
3130 if (acceptTokenClass(EHTokElse)) {
3131 // else statement
3132 if (! acceptScopedStatement(thenElse.node2)) {
3133 expected("else statement");
3134 return false;
3135 }
3136 }
3137
3138 // Put the pieces together
3139 statement = intermediate.addSelection(condition, thenElse, loc);
3140 parseContext.popScope();
3141
3142 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003143}
3144
John Kessenichd02dc5d2016-07-01 00:04:11 -06003145// switch_statement
3146// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
3147//
John Kessenich21472ae2016-06-04 11:46:33 -06003148bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
3149{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003150 // SWITCH
3151 TSourceLoc loc = token.loc;
3152 if (! acceptTokenClass(EHTokSwitch))
3153 return false;
3154
3155 // LEFT_PAREN expression RIGHT_PAREN
3156 parseContext.pushScope();
3157 TIntermTyped* switchExpression;
3158 if (! acceptParenExpression(switchExpression)) {
3159 parseContext.popScope();
3160 return false;
3161 }
3162
3163 // compound_statement
3164 parseContext.pushSwitchSequence(new TIntermSequence);
3165 bool statementOkay = acceptCompoundStatement(statement);
3166 if (statementOkay)
3167 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
3168
3169 parseContext.popSwitchSequence();
3170 parseContext.popScope();
3171
3172 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003173}
3174
John Kessenich119f8f62016-06-05 15:44:07 -06003175// iteration_statement
3176// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3177// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3178// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3179//
3180// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003181bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3182{
John Kessenich119f8f62016-06-05 15:44:07 -06003183 TSourceLoc loc = token.loc;
3184 TIntermTyped* condition = nullptr;
3185
3186 EHlslTokenClass loop = peek();
3187 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3188
3189 // WHILE or DO or FOR
3190 advanceToken();
3191
3192 switch (loop) {
3193 case EHTokWhile:
3194 // so that something declared in the condition is scoped to the lifetime
3195 // of the while sub-statement
3196 parseContext.pushScope();
3197 parseContext.nestLooping();
3198
3199 // LEFT_PAREN condition RIGHT_PAREN
3200 if (! acceptParenExpression(condition))
3201 return false;
3202
3203 // statement
3204 if (! acceptScopedStatement(statement)) {
3205 expected("while sub-statement");
3206 return false;
3207 }
3208
3209 parseContext.unnestLooping();
3210 parseContext.popScope();
3211
3212 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3213
3214 return true;
3215
3216 case EHTokDo:
3217 parseContext.nestLooping();
3218
3219 if (! acceptTokenClass(EHTokLeftBrace))
3220 expected("{");
3221
3222 // statement
3223 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3224 expected("do sub-statement");
3225 return false;
3226 }
3227
3228 if (! acceptTokenClass(EHTokRightBrace))
3229 expected("}");
3230
3231 // WHILE
3232 if (! acceptTokenClass(EHTokWhile)) {
3233 expected("while");
3234 return false;
3235 }
3236
3237 // LEFT_PAREN condition RIGHT_PAREN
3238 TIntermTyped* condition;
3239 if (! acceptParenExpression(condition))
3240 return false;
3241
3242 if (! acceptTokenClass(EHTokSemicolon))
3243 expected(";");
3244
3245 parseContext.unnestLooping();
3246
3247 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3248
3249 return true;
3250
3251 case EHTokFor:
3252 {
3253 // LEFT_PAREN
3254 if (! acceptTokenClass(EHTokLeftParen))
3255 expected("(");
3256
3257 // so that something declared in the condition is scoped to the lifetime
3258 // of the for sub-statement
3259 parseContext.pushScope();
3260
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003261 // initializer
3262 TIntermNode* initNode = nullptr;
3263 if (! acceptControlDeclaration(initNode)) {
3264 TIntermTyped* initExpr = nullptr;
3265 acceptExpression(initExpr);
3266 initNode = initExpr;
3267 }
3268 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003269 if (! acceptTokenClass(EHTokSemicolon))
3270 expected(";");
3271
3272 parseContext.nestLooping();
3273
3274 // condition SEMI_COLON
3275 acceptExpression(condition);
3276 if (! acceptTokenClass(EHTokSemicolon))
3277 expected(";");
3278
3279 // iterator SEMI_COLON
3280 TIntermTyped* iterator = nullptr;
3281 acceptExpression(iterator);
3282 if (! acceptTokenClass(EHTokRightParen))
3283 expected(")");
3284
3285 // statement
3286 if (! acceptScopedStatement(statement)) {
3287 expected("for sub-statement");
3288 return false;
3289 }
3290
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003291 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003292
3293 parseContext.popScope();
3294 parseContext.unnestLooping();
3295
3296 return true;
3297 }
3298
3299 default:
3300 return false;
3301 }
John Kessenich21472ae2016-06-04 11:46:33 -06003302}
3303
3304// jump_statement
3305// : CONTINUE SEMICOLON
3306// | BREAK SEMICOLON
3307// | DISCARD SEMICOLON
3308// | RETURN SEMICOLON
3309// | RETURN expression SEMICOLON
3310//
3311bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3312{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003313 EHlslTokenClass jump = peek();
3314 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003315 case EHTokContinue:
3316 case EHTokBreak:
3317 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003318 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003319 advanceToken();
3320 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003321 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003322 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003323 return false;
3324 }
John Kessenich21472ae2016-06-04 11:46:33 -06003325
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003326 switch (jump) {
3327 case EHTokContinue:
3328 statement = intermediate.addBranch(EOpContinue, token.loc);
3329 break;
3330 case EHTokBreak:
3331 statement = intermediate.addBranch(EOpBreak, token.loc);
3332 break;
3333 case EHTokDiscard:
3334 statement = intermediate.addBranch(EOpKill, token.loc);
3335 break;
3336
3337 case EHTokReturn:
3338 {
3339 // expression
3340 TIntermTyped* node;
3341 if (acceptExpression(node)) {
3342 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003343 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003344 } else
3345 statement = intermediate.addBranch(EOpReturn, token.loc);
3346 break;
3347 }
3348
3349 default:
3350 assert(0);
3351 return false;
3352 }
3353
3354 // SEMICOLON
3355 if (! acceptTokenClass(EHTokSemicolon))
3356 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003357
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003358 return true;
3359}
John Kessenich21472ae2016-06-04 11:46:33 -06003360
John Kessenichd02dc5d2016-07-01 00:04:11 -06003361// case_label
3362// : CASE expression COLON
3363//
John Kessenich21472ae2016-06-04 11:46:33 -06003364bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3365{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003366 TSourceLoc loc = token.loc;
3367 if (! acceptTokenClass(EHTokCase))
3368 return false;
3369
3370 TIntermTyped* expression;
3371 if (! acceptExpression(expression)) {
3372 expected("case expression");
3373 return false;
3374 }
3375
3376 if (! acceptTokenClass(EHTokColon)) {
3377 expected(":");
3378 return false;
3379 }
3380
3381 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3382
3383 return true;
3384}
3385
3386// default_label
3387// : DEFAULT COLON
3388//
3389bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3390{
3391 TSourceLoc loc = token.loc;
3392 if (! acceptTokenClass(EHTokDefault))
3393 return false;
3394
3395 if (! acceptTokenClass(EHTokColon)) {
3396 expected(":");
3397 return false;
3398 }
3399
3400 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3401
3402 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003403}
3404
John Kessenich19b92ff2016-06-19 11:50:34 -06003405// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003406// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3407// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003408//
3409void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3410{
3411 arraySizes = nullptr;
3412
steve-lunarg7b211a32016-10-13 12:26:18 -06003413 // Early-out if there aren't any array dimensions
3414 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003415 return;
3416
steve-lunarg7b211a32016-10-13 12:26:18 -06003417 // 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 -06003418 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003419
3420 // Collect each array dimension.
3421 while (acceptTokenClass(EHTokLeftBracket)) {
3422 TSourceLoc loc = token.loc;
3423 TIntermTyped* sizeExpr = nullptr;
3424
John Kessenich057df292017-03-06 18:18:37 -07003425 // Array sizing expression is optional. If omitted, array will be later sized by initializer list.
steve-lunarg7b211a32016-10-13 12:26:18 -06003426 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3427
3428 if (! acceptTokenClass(EHTokRightBracket)) {
3429 expected("]");
3430 return;
3431 }
3432
3433 if (hasArraySize) {
3434 TArraySize arraySize;
3435 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3436 arraySizes->addInnerSize(arraySize);
3437 } else {
3438 arraySizes->addInnerSize(0); // sized by initializers.
3439 }
steve-lunarg265c0612016-09-27 10:57:35 -06003440 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003441}
3442
John Kessenich630dd7d2016-06-12 23:52:12 -06003443// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003444// : COLON semantic // optional
3445// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3446// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003447// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003448// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003449//
John Kessenich854fe242017-03-02 14:30:59 -07003450// Return true if any tokens were accepted. That is,
3451// false can be returned on successfully recognizing nothing,
3452// not necessarily meaning bad syntax.
3453//
3454bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003455{
John Kessenich854fe242017-03-02 14:30:59 -07003456 bool found = false;
3457
John Kessenich630dd7d2016-06-12 23:52:12 -06003458 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003459 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003460 if (acceptTokenClass(EHTokColon)) {
John Kessenich854fe242017-03-02 14:30:59 -07003461 found = true;
John Kessenich630dd7d2016-06-12 23:52:12 -06003462 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003463 if (peekTokenClass(EHTokLayout))
3464 acceptLayoutQualifierList(qualifier);
3465 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003466 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003467 if (! acceptTokenClass(EHTokLeftParen)) {
3468 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003469 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003470 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003471 HlslToken locationToken;
3472 if (! acceptIdentifier(locationToken)) {
3473 expected("c[subcomponent][.component]");
John Kessenich854fe242017-03-02 14:30:59 -07003474 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003475 }
3476 HlslToken componentToken;
3477 if (acceptTokenClass(EHTokDot)) {
3478 if (! acceptIdentifier(componentToken)) {
3479 expected("component");
John Kessenich854fe242017-03-02 14:30:59 -07003480 return false;
John Kessenich82d6baf2016-07-29 13:03:05 -06003481 }
3482 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003483 if (! acceptTokenClass(EHTokRightParen)) {
3484 expected(")");
3485 break;
3486 }
John Kessenich7735b942016-09-05 12:40:06 -06003487 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003488 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003489 expected("layout, semantic, packoffset, or register");
John Kessenich854fe242017-03-02 14:30:59 -07003490 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003491 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003492 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3493 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003494 if (! acceptTokenClass(EHTokLeftParen)) {
3495 expected("(");
John Kessenich854fe242017-03-02 14:30:59 -07003496 return false;
John Kessenich630dd7d2016-06-12 23:52:12 -06003497 }
John Kessenichb38f0712016-07-30 10:29:54 -06003498 HlslToken registerDesc; // for Type#
3499 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003500 if (! acceptIdentifier(registerDesc)) {
3501 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003502 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003503 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003504 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3505 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003506 // Then we didn't really see the registerDesc yet, it was
3507 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003508 profile = registerDesc;
3509 if (! acceptIdentifier(registerDesc)) {
3510 expected("register number description");
John Kessenich854fe242017-03-02 14:30:59 -07003511 return false;
John Kessenich96e9f472016-07-29 14:28:39 -06003512 }
3513 }
John Kessenichb38f0712016-07-30 10:29:54 -06003514 int subComponent = 0;
3515 if (acceptTokenClass(EHTokLeftBracket)) {
3516 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3517 if (! peekTokenClass(EHTokIntConstant)) {
3518 expected("literal integer");
John Kessenich854fe242017-03-02 14:30:59 -07003519 return false;
John Kessenichb38f0712016-07-30 10:29:54 -06003520 }
3521 subComponent = token.i;
3522 advanceToken();
3523 if (! acceptTokenClass(EHTokRightBracket)) {
3524 expected("]");
3525 break;
3526 }
3527 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003528 // (COMMA SPACEN)opt
3529 HlslToken spaceDesc;
3530 if (acceptTokenClass(EHTokComma)) {
3531 if (! acceptIdentifier(spaceDesc)) {
3532 expected ("space identifier");
John Kessenich854fe242017-03-02 14:30:59 -07003533 return false;
John Kessenichcfd7ce82016-09-05 16:03:12 -06003534 }
3535 }
3536 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003537 if (! acceptTokenClass(EHTokRightParen)) {
3538 expected(")");
3539 break;
3540 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003541 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003542 } else {
3543 // semantic, in idToken.string
John Kessenich2dd643f2017-03-14 21:50:06 -06003544 TString semanticUpperCase = *idToken.string;
3545 std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper);
3546 parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase);
John Kessenich630dd7d2016-06-12 23:52:12 -06003547 }
John Kessenich854fe242017-03-02 14:30:59 -07003548 } else if (peekTokenClass(EHTokLeftAngle)) {
3549 found = true;
John Kessenicha1e2d492016-09-20 13:22:58 -06003550 acceptAnnotations(qualifier);
John Kessenich854fe242017-03-02 14:30:59 -07003551 } else
John Kessenich630dd7d2016-06-12 23:52:12 -06003552 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003553
John Kessenich630dd7d2016-06-12 23:52:12 -06003554 } while (true);
John Kessenich854fe242017-03-02 14:30:59 -07003555
3556 return found;
John Kessenich078d7f22016-03-14 10:02:11 -06003557}
3558
John Kessenichb16f7e62017-03-11 19:32:47 -07003559//
3560// Get the stream of tokens from the scanner, but skip all syntactic/semantic
3561// processing.
3562//
3563bool HlslGrammar::captureBlockTokens(TVector<HlslToken>& tokens)
3564{
3565 if (! peekTokenClass(EHTokLeftBrace))
3566 return false;
3567
3568 int braceCount = 0;
3569
3570 do {
3571 switch (peek()) {
3572 case EHTokLeftBrace:
3573 ++braceCount;
3574 break;
3575 case EHTokRightBrace:
3576 --braceCount;
3577 break;
3578 case EHTokNone:
3579 // End of input before balance { } is bad...
3580 return false;
3581 default:
3582 break;
3583 }
3584
3585 tokens.push_back(token);
3586 advanceToken();
3587 } while (braceCount > 0);
3588
3589 return true;
3590}
3591
John Kesseniche01a9bc2016-03-12 20:11:22 -07003592} // end namespace glslang