blob: 840d4ea56e677fc611c4ddc826babf1aa70fe089 [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 Kessenich02467d82017-01-19 15:41:47 -0700134 TIntermNode* declarationNode1;
135 TIntermNode* declarationNode2 = nullptr; // sometimes the grammar for a single declaration creates two
136 if (! acceptDeclaration(declarationNode1, declarationNode2))
John Kesseniche01a9bc2016-03-12 20:11:22 -0700137 return false;
John Kessenichd016be12016-03-13 11:24:20 -0600138
139 // hook it up
John Kessenich02467d82017-01-19 15:41:47 -0700140 unitNode = intermediate.growAggregate(unitNode, declarationNode1);
141 if (declarationNode2 != nullptr)
142 unitNode = intermediate.growAggregate(unitNode, declarationNode2);
John Kesseniche01a9bc2016-03-12 20:11:22 -0700143 }
144
John Kessenichd016be12016-03-13 11:24:20 -0600145 // set root of AST
John Kessenich078d7f22016-03-14 10:02:11 -0600146 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600147
John Kesseniche01a9bc2016-03-12 20:11:22 -0700148 return true;
149}
150
LoopDawg4886f692016-06-29 10:58:58 -0600151// sampler_state
John Kessenichecba76f2017-01-06 00:34:48 -0700152// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
LoopDawg4886f692016-06-29 10:58:58 -0600153//
154// sampler_state_assignment
155// : sampler_state_identifier EQUAL value SEMICOLON
156//
157// sampler_state_identifier
158// : ADDRESSU
159// | ADDRESSV
160// | ADDRESSW
161// | BORDERCOLOR
162// | FILTER
163// | MAXANISOTROPY
164// | MAXLOD
165// | MINLOD
166// | MIPLODBIAS
167//
168bool HlslGrammar::acceptSamplerState()
169{
170 // TODO: this should be genericized to accept a list of valid tokens and
171 // return token/value pairs. Presently it is specific to texture values.
172
173 if (! acceptTokenClass(EHTokLeftBrace))
174 return true;
175
176 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
John Kessenichecba76f2017-01-06 00:34:48 -0700177
LoopDawg4886f692016-06-29 10:58:58 -0600178 do {
179 // read state name
180 HlslToken state;
181 if (! acceptIdentifier(state))
182 break; // end of list
183
184 // FXC accepts any case
185 TString stateName = *state.string;
186 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
187
188 if (! acceptTokenClass(EHTokAssign)) {
189 expected("assign");
190 return false;
191 }
192
193 if (stateName == "minlod" || stateName == "maxlod") {
194 if (! peekTokenClass(EHTokIntConstant)) {
195 expected("integer");
196 return false;
197 }
198
199 TIntermTyped* lod = nullptr;
200 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
201 return false;
202 } else if (stateName == "maxanisotropy") {
203 if (! peekTokenClass(EHTokIntConstant)) {
204 expected("integer");
205 return false;
206 }
207
208 TIntermTyped* maxAnisotropy = nullptr;
209 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
210 return false;
211 } else if (stateName == "filter") {
212 HlslToken filterMode;
213 if (! acceptIdentifier(filterMode)) {
214 expected("filter mode");
215 return false;
216 }
217 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
218 HlslToken addrMode;
219 if (! acceptIdentifier(addrMode)) {
220 expected("texture address mode");
221 return false;
222 }
223 } else if (stateName == "miplodbias") {
224 TIntermTyped* lodBias = nullptr;
225 if (! acceptLiteral(lodBias)) {
226 expected("lod bias");
227 return false;
228 }
229 } else if (stateName == "bordercolor") {
230 return false;
231 } else {
232 expected("texture state");
233 return false;
234 }
235
236 // SEMICOLON
237 if (! acceptTokenClass(EHTokSemicolon)) {
238 expected("semicolon");
239 return false;
240 }
241 } while (true);
242
243 if (! acceptTokenClass(EHTokRightBrace))
244 return false;
245
246 return true;
247}
248
249// sampler_declaration_dx9
250// : SAMPLER identifier EQUAL sampler_type sampler_state
251//
John Kesseniche4821e42016-07-16 10:19:43 -0600252bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600253{
254 if (! acceptTokenClass(EHTokSampler))
255 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700256
LoopDawg4886f692016-06-29 10:58:58 -0600257 // TODO: remove this when DX9 style declarations are implemented.
258 unimplemented("Direct3D 9 sampler declaration");
259
260 // read sampler name
261 HlslToken name;
262 if (! acceptIdentifier(name)) {
263 expected("sampler name");
264 return false;
265 }
266
267 if (! acceptTokenClass(EHTokAssign)) {
268 expected("=");
269 return false;
270 }
271
272 return false;
273}
274
John Kesseniche01a9bc2016-03-12 20:11:22 -0700275// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600276// : sampler_declaration_dx9 post_decls SEMICOLON
277// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600278// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600279// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600280// | typedef declaration
John Kessenich87142c72016-03-12 20:24:24 -0700281//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600282// declarator_list
283// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600284//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600285// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600286// : identifier array_specifier post_decls
287// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600288// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600289//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600290// Parsing has to go pretty far in to know whether it's a variable, prototype, or
291// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600292// as above. (The 'identifier' in the first item in init_declarator list is the
293// same as 'identifier' for function declarations.)
294//
295// 'node' could get populated if the declaration creates code, like an initializer
John Kessenichd016be12016-03-13 11:24:20 -0600296// or a function body.
297//
John Kessenich02467d82017-01-19 15:41:47 -0700298// 'node2' could get populated with a second decoration tree if a single source declaration
299// leads to two subtrees that need to be peers higher up.
300//
John Kessenichd016be12016-03-13 11:24:20 -0600301bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700302{
John Kessenich02467d82017-01-19 15:41:47 -0700303 TIntermNode* node2;
304 return acceptDeclaration(node, node2);
305}
306bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
307{
John Kessenichd016be12016-03-13 11:24:20 -0600308 node = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -0700309 node2 = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600310 bool list = false;
John Kessenichd016be12016-03-13 11:24:20 -0600311
steve-lunarg1868b142016-10-20 13:07:10 -0600312 // attributes
313 TAttributeMap attributes;
314 acceptAttributes(attributes);
315
John Kessenich5e69ec62016-07-05 00:02:40 -0600316 // typedef
317 bool typedefDecl = acceptTokenClass(EHTokTypedef);
318
John Kesseniche82061d2016-09-27 14:38:57 -0600319 TType declaredType;
LoopDawg4886f692016-06-29 10:58:58 -0600320
321 // DX9 sampler declaration use a different syntax
John Kessenich267590d2016-08-05 17:34:34 -0600322 // DX9 shaders need to run through HLSL compiler (fxc) via a back compat mode, it isn't going to
323 // be possible to simultaneously compile D3D10+ style shaders and DX9 shaders. If we want to compile DX9
324 // HLSL shaders, this will have to be a master level switch
325 // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
John Kessenichecba76f2017-01-06 00:34:48 -0700326 // For that reason, this line is commented out
Dan Bakerc7e50162016-08-05 14:52:38 -0400327
John Kesseniche82061d2016-09-27 14:38:57 -0600328 // if (acceptSamplerDeclarationDX9(declaredType))
Dan Bakerc7e50162016-08-05 14:52:38 -0400329 // return true;
LoopDawg4886f692016-06-29 10:58:58 -0600330
331 // fully_specified_type
John Kesseniche82061d2016-09-27 14:38:57 -0600332 if (! acceptFullySpecifiedType(declaredType))
John Kessenich87142c72016-03-12 20:24:24 -0700333 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600334
John Kessenich87142c72016-03-12 20:24:24 -0700335 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600336 HlslToken idToken;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600337 while (acceptIdentifier(idToken)) {
steve-lunargf1e0c872016-10-31 15:13:43 -0600338 TString* fnName = idToken.string;
339
340 // Potentially rename shader entry point function. No-op most of the time.
341 parseContext.renameShaderFunction(fnName);
342
John Kessenich5f934b02016-03-13 17:58:25 -0600343 // function_parameters
steve-lunargf1e0c872016-10-31 15:13:43 -0600344 TFunction& function = *new TFunction(fnName, declaredType);
John Kessenich9e079532016-09-02 20:05:19 -0600345 if (acceptFunctionParameters(function)) {
John Kessenich630dd7d2016-06-12 23:52:12 -0600346 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -0600347 acceptPostDecls(function.getWritableType().getQualifier());
John Kessenich078d7f22016-03-14 10:02:11 -0600348
John Kessenichd5ed0b62016-07-04 17:32:45 -0600349 // compound_statement (function body definition) or just a prototype?
350 if (peekTokenClass(EHTokLeftBrace)) {
351 if (list)
352 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600353 if (typedefDecl)
354 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenich02467d82017-01-19 15:41:47 -0700355 return acceptFunctionDefinition(function, node, node2, attributes);
John Kessenich5e69ec62016-07-05 00:02:40 -0600356 } else {
357 if (typedefDecl)
358 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenich9e079532016-09-02 20:05:19 -0600359 parseContext.handleFunctionDeclarator(idToken.loc, function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600360 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600361 } else {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600362 // A variable declaration. Fix the storage qualifier if it's a global.
363 if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
364 declaredType.getQualifier().storage = EvqUniform;
365
John Kessenichecba76f2017-01-06 00:34:48 -0700366 // We can handle multiple variables per type declaration, so
John Kesseniche82061d2016-09-27 14:38:57 -0600367 // the number of types can expand when arrayness is different.
368 TType variableType;
369 variableType.shallowCopy(declaredType);
John Kessenich5f934b02016-03-13 17:58:25 -0600370
John Kesseniche82061d2016-09-27 14:38:57 -0600371 // recognize array_specifier
John Kessenichd5ed0b62016-07-04 17:32:45 -0600372 TArraySizes* arraySizes = nullptr;
373 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600374
John Kesseniche82061d2016-09-27 14:38:57 -0600375 // Fix arrayness in the variableType
376 if (declaredType.isImplicitlySizedArray()) {
377 // Because "int[] a = int[2](...), b = int[3](...)" makes two arrays a and b
378 // of different sizes, for this case sharing the shallow copy of arrayness
379 // with the parseType oversubscribes it, so get a deep copy of the arrayness.
380 variableType.newArraySizes(declaredType.getArraySizes());
381 }
382 if (arraySizes || variableType.isArray()) {
383 // In the most general case, arrayness is potentially coming both from the
384 // declared type and from the variable: "int[] a[];" or just one or the other.
385 // Merge it all to the variableType, so all arrayness is part of the variableType.
386 parseContext.arrayDimMerge(variableType, arraySizes);
387 }
388
LoopDawg4886f692016-06-29 10:58:58 -0600389 // samplers accept immediate sampler state
John Kesseniche82061d2016-09-27 14:38:57 -0600390 if (variableType.getBasicType() == EbtSampler) {
LoopDawg4886f692016-06-29 10:58:58 -0600391 if (! acceptSamplerState())
392 return false;
393 }
394
John Kessenichd5ed0b62016-07-04 17:32:45 -0600395 // post_decls
John Kesseniche82061d2016-09-27 14:38:57 -0600396 acceptPostDecls(variableType.getQualifier());
John Kessenichd5ed0b62016-07-04 17:32:45 -0600397
398 // EQUAL assignment_expression
399 TIntermTyped* expressionNode = nullptr;
400 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600401 if (typedefDecl)
402 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600403 if (! acceptAssignmentExpression(expressionNode)) {
404 expected("initializer");
405 return false;
406 }
407 }
408
John Kessenich6dbc0a72016-09-27 19:13:05 -0600409 // TODO: things scoped within an annotation need their own name space;
410 // TODO: strings are not yet handled.
411 if (variableType.getBasicType() != EbtString && parseContext.getAnnotationNestingLevel() == 0) {
412 if (typedefDecl)
413 parseContext.declareTypedef(idToken.loc, *idToken.string, variableType);
414 else if (variableType.getBasicType() == EbtBlock)
steve-lunargdd8287a2017-02-23 18:04:12 -0700415 parseContext.declareBlock(idToken.loc, variableType, idToken.string);
John Kessenich6dbc0a72016-09-27 19:13:05 -0600416 else {
steve-lunarga2b01a02016-11-28 17:09:54 -0700417 if (variableType.getQualifier().storage == EvqUniform && ! variableType.containsOpaque()) {
John Kessenich6dbc0a72016-09-27 19:13:05 -0600418 // this isn't really an individual variable, but a member of the $Global buffer
419 parseContext.growGlobalUniformBlock(idToken.loc, variableType, *idToken.string);
420 } else {
421 // Declare the variable and add any initializer code to the AST.
422 // The top-level node is always made into an aggregate, as that's
423 // historically how the AST has been.
424 node = intermediate.growAggregate(node,
425 parseContext.declareVariable(idToken.loc, *idToken.string, variableType,
426 expressionNode),
427 idToken.loc);
428 }
429 }
John Kessenich5e69ec62016-07-05 00:02:40 -0600430 }
John Kessenich5f934b02016-03-13 17:58:25 -0600431 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600432
433 if (acceptTokenClass(EHTokComma)) {
434 list = true;
435 continue;
436 }
437 };
438
439 // The top-level node is a sequence.
440 if (node != nullptr)
441 node->getAsAggregate()->setOperator(EOpSequence);
John Kessenich87142c72016-03-12 20:24:24 -0700442
John Kessenich078d7f22016-03-14 10:02:11 -0600443 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600444 if (! acceptTokenClass(EHTokSemicolon)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -0700445 // This may have been a false detection of what appeared to be a declaration, but
446 // was actually an assignment such as "float = 4", where "float" is an identifier.
447 // We put the token back to let further parsing happen for cases where that may
448 // happen. This errors on the side of caution, and mostly triggers the error.
449
450 if (peek() == EHTokAssign || peek() == EHTokLeftBracket || peek() == EHTokDot || peek() == EHTokComma)
451 recedeToken();
452 else
453 expected(";");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600454 return false;
455 }
John Kessenichecba76f2017-01-06 00:34:48 -0700456
John Kesseniche01a9bc2016-03-12 20:11:22 -0700457 return true;
458}
459
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600460// control_declaration
461// : fully_specified_type identifier EQUAL expression
462//
463bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
464{
465 node = nullptr;
466
467 // fully_specified_type
468 TType type;
469 if (! acceptFullySpecifiedType(type))
470 return false;
471
472 // identifier
473 HlslToken idToken;
474 if (! acceptIdentifier(idToken)) {
475 expected("identifier");
476 return false;
477 }
478
479 // EQUAL
480 TIntermTyped* expressionNode = nullptr;
481 if (! acceptTokenClass(EHTokAssign)) {
482 expected("=");
483 return false;
484 }
485
486 // expression
487 if (! acceptExpression(expressionNode)) {
488 expected("initializer");
489 return false;
490 }
491
John Kesseniche82061d2016-09-27 14:38:57 -0600492 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, expressionNode);
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600493
494 return true;
495}
496
John Kessenich87142c72016-03-12 20:24:24 -0700497// fully_specified_type
498// : type_specifier
499// | type_qualifier type_specifier
500//
501bool HlslGrammar::acceptFullySpecifiedType(TType& type)
502{
503 // type_qualifier
504 TQualifier qualifier;
505 qualifier.clear();
John Kessenichb9e39122016-08-17 10:22:08 -0600506 if (! acceptQualifier(qualifier))
507 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600508 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700509
510 // type_specifier
steve-lunarga64ed3e2016-12-18 17:51:14 -0700511 if (! acceptType(type)) {
512 // If this is not a type, we may have inadvertently gone down a wrong path
steve-lunarg132d3312016-12-19 15:48:01 -0700513 // by parsing "sample", which can be treated like either an identifier or a
steve-lunarga64ed3e2016-12-18 17:51:14 -0700514 // qualifier. Back it out, if we did.
515 if (qualifier.sample)
516 recedeToken();
517
John Kessenich87142c72016-03-12 20:24:24 -0700518 return false;
steve-lunarga64ed3e2016-12-18 17:51:14 -0700519 }
John Kessenich3d157c52016-07-25 16:05:33 -0600520 if (type.getBasicType() == EbtBlock) {
521 // the type was a block, which set some parts of the qualifier
John Kessenich34e7ee72016-09-16 17:10:39 -0600522 parseContext.mergeQualifiers(type.getQualifier(), qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600523 // further, it can create an anonymous instance of the block
524 if (peekTokenClass(EHTokSemicolon))
525 parseContext.declareBlock(loc, type);
steve-lunargbb0183f2016-10-04 16:58:14 -0600526 } else {
527 // Some qualifiers are set when parsing the type. Merge those with
528 // whatever comes from acceptQualifier.
529 assert(qualifier.layoutFormat == ElfNone);
steve-lunargf49cdf42016-11-17 15:04:20 -0700530
steve-lunargbb0183f2016-10-04 16:58:14 -0600531 qualifier.layoutFormat = type.getQualifier().layoutFormat;
steve-lunarg3226b082016-10-26 19:18:55 -0600532 qualifier.precision = type.getQualifier().precision;
steve-lunargf49cdf42016-11-17 15:04:20 -0700533
steve-lunarg5da1f032017-02-12 17:50:28 -0700534 if (type.getQualifier().storage == EvqVaryingOut ||
535 type.getQualifier().storage == EvqBuffer) {
steve-lunargf49cdf42016-11-17 15:04:20 -0700536 qualifier.storage = type.getQualifier().storage;
steve-lunarg5da1f032017-02-12 17:50:28 -0700537 qualifier.readonly = type.getQualifier().readonly;
538 }
steve-lunargf49cdf42016-11-17 15:04:20 -0700539
540 type.getQualifier() = qualifier;
steve-lunargbb0183f2016-10-04 16:58:14 -0600541 }
John Kessenich87142c72016-03-12 20:24:24 -0700542
543 return true;
544}
545
John Kessenich630dd7d2016-06-12 23:52:12 -0600546// type_qualifier
547// : qualifier qualifier ...
548//
549// Zero or more of these, so this can't return false.
550//
John Kessenichb9e39122016-08-17 10:22:08 -0600551bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
John Kessenich87142c72016-03-12 20:24:24 -0700552{
John Kessenich630dd7d2016-06-12 23:52:12 -0600553 do {
554 switch (peek()) {
555 case EHTokStatic:
John Kessenich6dbc0a72016-09-27 19:13:05 -0600556 qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
John Kessenich630dd7d2016-06-12 23:52:12 -0600557 break;
558 case EHTokExtern:
559 // TODO: no meaning in glslang?
560 break;
561 case EHTokShared:
562 // TODO: hint
563 break;
564 case EHTokGroupShared:
565 qualifier.storage = EvqShared;
566 break;
567 case EHTokUniform:
568 qualifier.storage = EvqUniform;
569 break;
570 case EHTokConst:
571 qualifier.storage = EvqConst;
572 break;
573 case EHTokVolatile:
574 qualifier.volatil = true;
575 break;
576 case EHTokLinear:
John Kessenich630dd7d2016-06-12 23:52:12 -0600577 qualifier.smooth = true;
578 break;
579 case EHTokCentroid:
580 qualifier.centroid = true;
581 break;
582 case EHTokNointerpolation:
583 qualifier.flat = true;
584 break;
585 case EHTokNoperspective:
586 qualifier.nopersp = true;
587 break;
588 case EHTokSample:
589 qualifier.sample = true;
590 break;
591 case EHTokRowMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600592 qualifier.layoutMatrix = ElmColumnMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600593 break;
594 case EHTokColumnMajor:
John Kessenich10f7fc72016-09-25 20:25:06 -0600595 qualifier.layoutMatrix = ElmRowMajor;
John Kessenich630dd7d2016-06-12 23:52:12 -0600596 break;
597 case EHTokPrecise:
598 qualifier.noContraction = true;
599 break;
LoopDawg9249c702016-07-12 20:44:32 -0600600 case EHTokIn:
601 qualifier.storage = EvqIn;
602 break;
603 case EHTokOut:
604 qualifier.storage = EvqOut;
605 break;
606 case EHTokInOut:
607 qualifier.storage = EvqInOut;
608 break;
John Kessenichb9e39122016-08-17 10:22:08 -0600609 case EHTokLayout:
610 if (! acceptLayoutQualifierList(qualifier))
611 return false;
612 continue;
steve-lunarg5da1f032017-02-12 17:50:28 -0700613 case EHTokGloballyCoherent:
614 qualifier.coherent = true;
615 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700616
617 // GS geometries: these are specified on stage input variables, and are an error (not verified here)
618 // for output variables.
619 case EHTokPoint:
620 qualifier.storage = EvqIn;
621 if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
622 return false;
623 break;
624 case EHTokLine:
625 qualifier.storage = EvqIn;
626 if (!parseContext.handleInputGeometry(token.loc, ElgLines))
627 return false;
628 break;
629 case EHTokTriangle:
630 qualifier.storage = EvqIn;
631 if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
632 return false;
633 break;
634 case EHTokLineAdj:
635 qualifier.storage = EvqIn;
636 if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
637 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700638 break;
steve-lunargf49cdf42016-11-17 15:04:20 -0700639 case EHTokTriangleAdj:
640 qualifier.storage = EvqIn;
641 if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
642 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700643 break;
644
John Kessenich630dd7d2016-06-12 23:52:12 -0600645 default:
John Kessenichb9e39122016-08-17 10:22:08 -0600646 return true;
John Kessenich630dd7d2016-06-12 23:52:12 -0600647 }
648 advanceToken();
649 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700650}
651
John Kessenichb9e39122016-08-17 10:22:08 -0600652// layout_qualifier_list
John Kesseniche3218e22016-09-05 14:37:03 -0600653// : LAYOUT LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
John Kessenichb9e39122016-08-17 10:22:08 -0600654//
655// layout_qualifier
656// : identifier
John Kessenich841db352016-09-02 21:12:23 -0600657// | identifier EQUAL expression
John Kessenichb9e39122016-08-17 10:22:08 -0600658//
659// Zero or more of these, so this can't return false.
660//
661bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
662{
663 if (! acceptTokenClass(EHTokLayout))
664 return false;
665
666 // LEFT_PAREN
667 if (! acceptTokenClass(EHTokLeftParen))
668 return false;
669
670 do {
671 // identifier
672 HlslToken idToken;
673 if (! acceptIdentifier(idToken))
674 break;
675
676 // EQUAL expression
677 if (acceptTokenClass(EHTokAssign)) {
678 TIntermTyped* expr;
679 if (! acceptConditionalExpression(expr)) {
680 expected("expression");
681 return false;
682 }
683 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
684 } else
685 parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
686
687 // COMMA
688 if (! acceptTokenClass(EHTokComma))
689 break;
690 } while (true);
691
692 // RIGHT_PAREN
693 if (! acceptTokenClass(EHTokRightParen)) {
694 expected(")");
695 return false;
696 }
697
698 return true;
699}
700
LoopDawg6daaa4f2016-06-23 19:13:48 -0600701// template_type
702// : FLOAT
703// | DOUBLE
704// | INT
705// | DWORD
706// | UINT
707// | BOOL
708//
steve-lunargf49cdf42016-11-17 15:04:20 -0700709bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
LoopDawg6daaa4f2016-06-23 19:13:48 -0600710{
711 switch (peek()) {
712 case EHTokFloat:
713 basicType = EbtFloat;
714 break;
715 case EHTokDouble:
716 basicType = EbtDouble;
717 break;
718 case EHTokInt:
719 case EHTokDword:
720 basicType = EbtInt;
721 break;
722 case EHTokUint:
723 basicType = EbtUint;
724 break;
725 case EHTokBool:
726 basicType = EbtBool;
727 break;
728 default:
729 return false;
730 }
731
732 advanceToken();
733
734 return true;
735}
736
737// vector_template_type
738// : VECTOR
739// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
740//
741bool HlslGrammar::acceptVectorTemplateType(TType& type)
742{
743 if (! acceptTokenClass(EHTokVector))
744 return false;
745
746 if (! acceptTokenClass(EHTokLeftAngle)) {
747 // in HLSL, 'vector' alone means float4.
748 new(&type) TType(EbtFloat, EvqTemporary, 4);
749 return true;
750 }
751
752 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700753 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600754 expected("scalar type");
755 return false;
756 }
757
758 // COMMA
759 if (! acceptTokenClass(EHTokComma)) {
760 expected(",");
761 return false;
762 }
763
764 // integer
765 if (! peekTokenClass(EHTokIntConstant)) {
766 expected("literal integer");
767 return false;
768 }
769
770 TIntermTyped* vecSize;
771 if (! acceptLiteral(vecSize))
772 return false;
773
774 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
775
776 new(&type) TType(basicType, EvqTemporary, vecSizeI);
777
778 if (vecSizeI == 1)
779 type.makeVector();
780
781 if (!acceptTokenClass(EHTokRightAngle)) {
782 expected("right angle bracket");
783 return false;
784 }
785
786 return true;
787}
788
789// matrix_template_type
790// : MATRIX
791// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
792//
793bool HlslGrammar::acceptMatrixTemplateType(TType& type)
794{
795 if (! acceptTokenClass(EHTokMatrix))
796 return false;
797
798 if (! acceptTokenClass(EHTokLeftAngle)) {
799 // in HLSL, 'matrix' alone means float4x4.
800 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
801 return true;
802 }
803
804 TBasicType basicType;
steve-lunargf49cdf42016-11-17 15:04:20 -0700805 if (! acceptTemplateVecMatBasicType(basicType)) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600806 expected("scalar type");
807 return false;
808 }
809
810 // COMMA
811 if (! acceptTokenClass(EHTokComma)) {
812 expected(",");
813 return false;
814 }
815
816 // integer rows
817 if (! peekTokenClass(EHTokIntConstant)) {
818 expected("literal integer");
819 return false;
820 }
821
822 TIntermTyped* rows;
823 if (! acceptLiteral(rows))
824 return false;
825
826 // COMMA
827 if (! acceptTokenClass(EHTokComma)) {
828 expected(",");
829 return false;
830 }
John Kessenichecba76f2017-01-06 00:34:48 -0700831
LoopDawg6daaa4f2016-06-23 19:13:48 -0600832 // integer cols
833 if (! peekTokenClass(EHTokIntConstant)) {
834 expected("literal integer");
835 return false;
836 }
837
838 TIntermTyped* cols;
839 if (! acceptLiteral(cols))
840 return false;
841
842 new(&type) TType(basicType, EvqTemporary, 0,
steve-lunarg297ae212016-08-24 14:36:13 -0600843 rows->getAsConstantUnion()->getConstArray()[0].getIConst(),
844 cols->getAsConstantUnion()->getConstArray()[0].getIConst());
LoopDawg6daaa4f2016-06-23 19:13:48 -0600845
846 if (!acceptTokenClass(EHTokRightAngle)) {
847 expected("right angle bracket");
848 return false;
849 }
850
851 return true;
852}
853
steve-lunargf49cdf42016-11-17 15:04:20 -0700854// layout_geometry
855// : LINESTREAM
856// | POINTSTREAM
857// | TRIANGLESTREAM
858//
859bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
860{
861 // read geometry type
862 const EHlslTokenClass geometryType = peek();
863
864 switch (geometryType) {
865 case EHTokPointStream: geometry = ElgPoints; break;
866 case EHTokLineStream: geometry = ElgLineStrip; break;
867 case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
868 default:
869 return false; // not a layout geometry
870 }
871
872 advanceToken(); // consume the layout keyword
873 return true;
874}
875
steve-lunarg858c9282017-01-07 08:54:10 -0700876// tessellation_decl_type
877// : INPUTPATCH
878// | OUTPUTPATCH
879//
880bool HlslGrammar::acceptTessellationDeclType()
881{
882 // read geometry type
883 const EHlslTokenClass tessType = peek();
884
885 switch (tessType) {
886 case EHTokInputPatch: break;
887 case EHTokOutputPatch: break;
888 default:
889 return false; // not a tessellation decl
890 }
891
892 advanceToken(); // consume the keyword
893 return true;
894}
895
896// tessellation_patch_template_type
897// : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
898//
899bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
900{
901 if (! acceptTessellationDeclType())
902 return false;
903
904 if (! acceptTokenClass(EHTokLeftAngle))
905 return false;
906
907 if (! acceptType(type)) {
908 expected("tessellation patch type");
909 return false;
910 }
911
912 if (! acceptTokenClass(EHTokComma))
913 return false;
914
915 // integer size
916 if (! peekTokenClass(EHTokIntConstant)) {
917 expected("literal integer");
918 return false;
919 }
920
921 TIntermTyped* size;
922 if (! acceptLiteral(size))
923 return false;
924
925 TArraySizes* arraySizes = new TArraySizes;
926 arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
927 type.newArraySizes(*arraySizes);
928
929 if (! acceptTokenClass(EHTokRightAngle)) {
930 expected("right angle bracket");
931 return false;
932 }
933
934 return true;
935}
936
steve-lunargf49cdf42016-11-17 15:04:20 -0700937// stream_out_template_type
938// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
939//
940bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
941{
942 geometry = ElgNone;
943
944 if (! acceptOutputPrimitiveGeometry(geometry))
945 return false;
946
947 if (! acceptTokenClass(EHTokLeftAngle))
948 return false;
John Kessenichecba76f2017-01-06 00:34:48 -0700949
steve-lunargf49cdf42016-11-17 15:04:20 -0700950 if (! acceptType(type)) {
951 expected("stream output type");
952 return false;
953 }
954
955 type.getQualifier().storage = EvqVaryingOut;
956
957 if (! acceptTokenClass(EHTokRightAngle)) {
958 expected("right angle bracket");
959 return false;
960 }
961
962 return true;
963}
John Kessenichecba76f2017-01-06 00:34:48 -0700964
John Kessenicha1e2d492016-09-20 13:22:58 -0600965// annotations
966// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
John Kessenich86f71382016-09-19 20:23:18 -0600967//
John Kessenicha1e2d492016-09-20 13:22:58 -0600968bool HlslGrammar::acceptAnnotations(TQualifier&)
John Kessenich86f71382016-09-19 20:23:18 -0600969{
John Kessenicha1e2d492016-09-20 13:22:58 -0600970 if (! acceptTokenClass(EHTokLeftAngle))
John Kessenich86f71382016-09-19 20:23:18 -0600971 return false;
972
John Kessenicha1e2d492016-09-20 13:22:58 -0600973 // note that we are nesting a name space
974 parseContext.nestAnnotations();
John Kessenich86f71382016-09-19 20:23:18 -0600975
976 // declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
977 do {
978 // eat any extra SEMI_COLON; don't know if the grammar calls for this or not
979 while (acceptTokenClass(EHTokSemicolon))
980 ;
981
982 if (acceptTokenClass(EHTokRightAngle))
John Kessenicha1e2d492016-09-20 13:22:58 -0600983 break;
John Kessenich86f71382016-09-19 20:23:18 -0600984
985 // declaration
986 TIntermNode* node;
987 if (! acceptDeclaration(node)) {
John Kessenicha1e2d492016-09-20 13:22:58 -0600988 expected("declaration in annotation");
John Kessenich86f71382016-09-19 20:23:18 -0600989 return false;
990 }
991 } while (true);
John Kessenicha1e2d492016-09-20 13:22:58 -0600992
993 parseContext.unnestAnnotations();
994 return true;
John Kessenich86f71382016-09-19 20:23:18 -0600995}
LoopDawg6daaa4f2016-06-23 19:13:48 -0600996
LoopDawg4886f692016-06-29 10:58:58 -0600997// sampler_type
998// : SAMPLER
999// | SAMPLER1D
1000// | SAMPLER2D
1001// | SAMPLER3D
1002// | SAMPLERCUBE
1003// | SAMPLERSTATE
1004// | SAMPLERCOMPARISONSTATE
1005bool HlslGrammar::acceptSamplerType(TType& type)
1006{
1007 // read sampler type
1008 const EHlslTokenClass samplerType = peek();
1009
LoopDawga78b0292016-07-19 14:28:05 -06001010 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -06001011 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -06001012
LoopDawga78b0292016-07-19 14:28:05 -06001013 bool isShadow = false;
1014
LoopDawg4886f692016-06-29 10:58:58 -06001015 switch (samplerType) {
1016 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -06001017 case EHTokSampler1d: /*dim = Esd1D*/; break;
1018 case EHTokSampler2d: /*dim = Esd2D*/; break;
1019 case EHTokSampler3d: /*dim = Esd3D*/; break;
1020 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -06001021 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -06001022 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001023 default:
1024 return false; // not a sampler declaration
1025 }
1026
1027 advanceToken(); // consume the sampler type keyword
1028
1029 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -06001030
1031 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -06001032 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -06001033
1034 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
1035
1036 return true;
1037}
1038
1039// texture_type
1040// | BUFFER
1041// | TEXTURE1D
1042// | TEXTURE1DARRAY
1043// | TEXTURE2D
1044// | TEXTURE2DARRAY
1045// | TEXTURE3D
1046// | TEXTURECUBE
1047// | TEXTURECUBEARRAY
1048// | TEXTURE2DMS
1049// | TEXTURE2DMSARRAY
steve-lunargbb0183f2016-10-04 16:58:14 -06001050// | RWBUFFER
1051// | RWTEXTURE1D
1052// | RWTEXTURE1DARRAY
1053// | RWTEXTURE2D
1054// | RWTEXTURE2DARRAY
1055// | RWTEXTURE3D
1056
LoopDawg4886f692016-06-29 10:58:58 -06001057bool HlslGrammar::acceptTextureType(TType& type)
1058{
1059 const EHlslTokenClass textureType = peek();
1060
1061 TSamplerDim dim = EsdNone;
1062 bool array = false;
1063 bool ms = false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001064 bool image = false;
LoopDawg4886f692016-06-29 10:58:58 -06001065
1066 switch (textureType) {
1067 case EHTokBuffer: dim = EsdBuffer; break;
1068 case EHTokTexture1d: dim = Esd1D; break;
1069 case EHTokTexture1darray: dim = Esd1D; array = true; break;
1070 case EHTokTexture2d: dim = Esd2D; break;
1071 case EHTokTexture2darray: dim = Esd2D; array = true; break;
John Kessenichecba76f2017-01-06 00:34:48 -07001072 case EHTokTexture3d: dim = Esd3D; break;
LoopDawg4886f692016-06-29 10:58:58 -06001073 case EHTokTextureCube: dim = EsdCube; break;
1074 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
1075 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
1076 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
steve-lunargbb0183f2016-10-04 16:58:14 -06001077 case EHTokRWBuffer: dim = EsdBuffer; image=true; break;
1078 case EHTokRWTexture1d: dim = Esd1D; array=false; image=true; break;
1079 case EHTokRWTexture1darray: dim = Esd1D; array=true; image=true; break;
1080 case EHTokRWTexture2d: dim = Esd2D; array=false; image=true; break;
1081 case EHTokRWTexture2darray: dim = Esd2D; array=true; image=true; break;
1082 case EHTokRWTexture3d: dim = Esd3D; array=false; image=true; break;
LoopDawg4886f692016-06-29 10:58:58 -06001083 default:
1084 return false; // not a texture declaration
1085 }
1086
1087 advanceToken(); // consume the texture object keyword
1088
1089 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
John Kessenichecba76f2017-01-06 00:34:48 -07001090
LoopDawg4886f692016-06-29 10:58:58 -06001091 TIntermTyped* msCount = nullptr;
1092
steve-lunargbb0183f2016-10-04 16:58:14 -06001093 // texture type: required for multisample types and RWBuffer/RWTextures!
LoopDawg4886f692016-06-29 10:58:58 -06001094 if (acceptTokenClass(EHTokLeftAngle)) {
1095 if (! acceptType(txType)) {
1096 expected("scalar or vector type");
1097 return false;
1098 }
1099
1100 const TBasicType basicRetType = txType.getBasicType() ;
1101
1102 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
1103 unimplemented("basic type in texture");
1104 return false;
1105 }
1106
steve-lunargd53f7172016-07-27 15:46:48 -06001107 // Buffers can handle small mats if they fit in 4 components
1108 if (dim == EsdBuffer && txType.isMatrix()) {
1109 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
1110 expected("components < 4 in matrix buffer type");
1111 return false;
1112 }
1113
1114 // TODO: except we don't handle it yet...
1115 unimplemented("matrix type in buffer");
1116 return false;
1117 }
1118
LoopDawg4886f692016-06-29 10:58:58 -06001119 if (!txType.isScalar() && !txType.isVector()) {
1120 expected("scalar or vector type");
1121 return false;
1122 }
1123
LoopDawg4886f692016-06-29 10:58:58 -06001124 if (ms && acceptTokenClass(EHTokComma)) {
1125 // read sample count for multisample types, if given
1126 if (! peekTokenClass(EHTokIntConstant)) {
1127 expected("multisample count");
1128 return false;
1129 }
1130
1131 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
1132 return false;
1133 }
1134
1135 if (! acceptTokenClass(EHTokRightAngle)) {
1136 expected("right angle bracket");
1137 return false;
1138 }
1139 } else if (ms) {
1140 expected("texture type for multisample");
1141 return false;
steve-lunargbb0183f2016-10-04 16:58:14 -06001142 } else if (image) {
1143 expected("type for RWTexture/RWBuffer");
1144 return false;
LoopDawg4886f692016-06-29 10:58:58 -06001145 }
1146
1147 TArraySizes* arraySizes = nullptr;
steve-lunarg4f2da272016-10-10 15:24:57 -06001148 const bool shadow = false; // declared on the sampler
LoopDawg4886f692016-06-29 10:58:58 -06001149
1150 TSampler sampler;
steve-lunargbb0183f2016-10-04 16:58:14 -06001151 TLayoutFormat format = ElfNone;
steve-lunargd53f7172016-07-27 15:46:48 -06001152
steve-lunarg4f2da272016-10-10 15:24:57 -06001153 // Buffer, RWBuffer and RWTexture (images) require a TLayoutFormat. We handle only a limit set.
1154 if (image || dim == EsdBuffer)
1155 format = parseContext.getLayoutFromTxType(token.loc, txType);
steve-lunargbb0183f2016-10-04 16:58:14 -06001156
1157 // Non-image Buffers are combined
1158 if (dim == EsdBuffer && !image) {
steve-lunargd53f7172016-07-27 15:46:48 -06001159 sampler.set(txType.getBasicType(), dim, array);
1160 } else {
1161 // DX10 textures are separated. TODO: DX9.
steve-lunargbb0183f2016-10-04 16:58:14 -06001162 if (image) {
1163 sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
1164 } else {
1165 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
1166 }
steve-lunargd53f7172016-07-27 15:46:48 -06001167 }
steve-lunarg8b0227c2016-10-14 16:40:32 -06001168
1169 // Remember the declared vector size.
1170 sampler.vectorSize = txType.getVectorSize();
John Kessenichecba76f2017-01-06 00:34:48 -07001171
LoopDawg4886f692016-06-29 10:58:58 -06001172 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
steve-lunargbb0183f2016-10-04 16:58:14 -06001173 type.getQualifier().layoutFormat = format;
LoopDawg4886f692016-06-29 10:58:58 -06001174
1175 return true;
1176}
1177
John Kessenich87142c72016-03-12 20:24:24 -07001178// If token is for a type, update 'type' with the type information,
1179// and return true and advance.
1180// Otherwise, return false, and don't advance
1181bool HlslGrammar::acceptType(TType& type)
1182{
steve-lunarg3226b082016-10-26 19:18:55 -06001183 // Basic types for min* types, broken out here in case of future
1184 // changes, e.g, to use native halfs.
1185 static const TBasicType min16float_bt = EbtFloat;
1186 static const TBasicType min10float_bt = EbtFloat;
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001187 static const TBasicType half_bt = EbtFloat;
steve-lunarg3226b082016-10-26 19:18:55 -06001188 static const TBasicType min16int_bt = EbtInt;
1189 static const TBasicType min12int_bt = EbtInt;
1190 static const TBasicType min16uint_bt = EbtUint;
1191
John Kessenich9c86c6a2016-05-03 22:49:24 -06001192 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -06001193 case EHTokVector:
1194 return acceptVectorTemplateType(type);
1195 break;
1196
1197 case EHTokMatrix:
1198 return acceptMatrixTemplateType(type);
1199 break;
1200
steve-lunargf49cdf42016-11-17 15:04:20 -07001201 case EHTokPointStream: // fall through
1202 case EHTokLineStream: // ...
1203 case EHTokTriangleStream: // ...
1204 {
1205 TLayoutGeometry geometry;
1206 if (! acceptStreamOutTemplateType(type, geometry))
1207 return false;
1208
1209 if (! parseContext.handleOutputGeometry(token.loc, geometry))
1210 return false;
John Kessenichecba76f2017-01-06 00:34:48 -07001211
steve-lunargf49cdf42016-11-17 15:04:20 -07001212 return true;
1213 }
1214
steve-lunarg858c9282017-01-07 08:54:10 -07001215 case EHTokInputPatch: // fall through
1216 case EHTokOutputPatch: // ...
1217 {
1218 if (! acceptTessellationPatchTemplateType(type))
1219 return false;
1220
1221 return true;
1222 }
1223
LoopDawg4886f692016-06-29 10:58:58 -06001224 case EHTokSampler: // fall through
1225 case EHTokSampler1d: // ...
1226 case EHTokSampler2d: // ...
1227 case EHTokSampler3d: // ...
1228 case EHTokSamplerCube: // ...
1229 case EHTokSamplerState: // ...
1230 case EHTokSamplerComparisonState: // ...
1231 return acceptSamplerType(type);
1232 break;
1233
1234 case EHTokBuffer: // fall through
1235 case EHTokTexture1d: // ...
1236 case EHTokTexture1darray: // ...
1237 case EHTokTexture2d: // ...
1238 case EHTokTexture2darray: // ...
1239 case EHTokTexture3d: // ...
1240 case EHTokTextureCube: // ...
1241 case EHTokTextureCubearray: // ...
1242 case EHTokTexture2DMS: // ...
1243 case EHTokTexture2DMSarray: // ...
steve-lunargbb0183f2016-10-04 16:58:14 -06001244 case EHTokRWTexture1d: // ...
1245 case EHTokRWTexture1darray: // ...
1246 case EHTokRWTexture2d: // ...
1247 case EHTokRWTexture2darray: // ...
1248 case EHTokRWTexture3d: // ...
1249 case EHTokRWBuffer: // ...
LoopDawg4886f692016-06-29 10:58:58 -06001250 return acceptTextureType(type);
1251 break;
1252
steve-lunarg5da1f032017-02-12 17:50:28 -07001253 case EHTokAppendStructuredBuffer:
1254 case EHTokByteAddressBuffer:
1255 case EHTokConsumeStructuredBuffer:
1256 case EHTokRWByteAddressBuffer:
1257 case EHTokRWStructuredBuffer:
1258 case EHTokStructuredBuffer:
1259 return acceptStructBufferType(type);
1260 break;
1261
John Kesseniche6e74942016-06-11 16:43:14 -06001262 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -06001263 case EHTokCBuffer:
1264 case EHTokTBuffer:
John Kesseniche6e74942016-06-11 16:43:14 -06001265 return acceptStruct(type);
John Kesseniche6e74942016-06-11 16:43:14 -06001266
1267 case EHTokIdentifier:
1268 // An identifier could be for a user-defined type.
1269 // Note we cache the symbol table lookup, to save for a later rule
1270 // when this is not a type.
1271 token.symbol = parseContext.symbolTable.find(*token.string);
1272 if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
1273 type.shallowCopy(token.symbol->getType());
1274 advanceToken();
1275 return true;
1276 } else
1277 return false;
1278
John Kessenich71351de2016-06-08 12:50:56 -06001279 case EHTokVoid:
1280 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -07001281 break;
John Kessenich71351de2016-06-08 12:50:56 -06001282
John Kessenicha1e2d492016-09-20 13:22:58 -06001283 case EHTokString:
1284 new(&type) TType(EbtString);
1285 break;
1286
John Kessenich87142c72016-03-12 20:24:24 -07001287 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -06001288 new(&type) TType(EbtFloat);
1289 break;
John Kessenich87142c72016-03-12 20:24:24 -07001290 case EHTokFloat1:
1291 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -06001292 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -07001293 break;
John Kessenich87142c72016-03-12 20:24:24 -07001294 case EHTokFloat2:
1295 new(&type) TType(EbtFloat, EvqTemporary, 2);
1296 break;
1297 case EHTokFloat3:
1298 new(&type) TType(EbtFloat, EvqTemporary, 3);
1299 break;
1300 case EHTokFloat4:
1301 new(&type) TType(EbtFloat, EvqTemporary, 4);
1302 break;
1303
John Kessenich71351de2016-06-08 12:50:56 -06001304 case EHTokDouble:
1305 new(&type) TType(EbtDouble);
1306 break;
1307 case EHTokDouble1:
1308 new(&type) TType(EbtDouble);
1309 type.makeVector();
1310 break;
1311 case EHTokDouble2:
1312 new(&type) TType(EbtDouble, EvqTemporary, 2);
1313 break;
1314 case EHTokDouble3:
1315 new(&type) TType(EbtDouble, EvqTemporary, 3);
1316 break;
1317 case EHTokDouble4:
1318 new(&type) TType(EbtDouble, EvqTemporary, 4);
1319 break;
1320
1321 case EHTokInt:
1322 case EHTokDword:
1323 new(&type) TType(EbtInt);
1324 break;
1325 case EHTokInt1:
1326 new(&type) TType(EbtInt);
1327 type.makeVector();
1328 break;
John Kessenich87142c72016-03-12 20:24:24 -07001329 case EHTokInt2:
1330 new(&type) TType(EbtInt, EvqTemporary, 2);
1331 break;
1332 case EHTokInt3:
1333 new(&type) TType(EbtInt, EvqTemporary, 3);
1334 break;
1335 case EHTokInt4:
1336 new(&type) TType(EbtInt, EvqTemporary, 4);
1337 break;
1338
John Kessenich71351de2016-06-08 12:50:56 -06001339 case EHTokUint:
1340 new(&type) TType(EbtUint);
1341 break;
1342 case EHTokUint1:
1343 new(&type) TType(EbtUint);
1344 type.makeVector();
1345 break;
1346 case EHTokUint2:
1347 new(&type) TType(EbtUint, EvqTemporary, 2);
1348 break;
1349 case EHTokUint3:
1350 new(&type) TType(EbtUint, EvqTemporary, 3);
1351 break;
1352 case EHTokUint4:
1353 new(&type) TType(EbtUint, EvqTemporary, 4);
1354 break;
1355
1356 case EHTokBool:
1357 new(&type) TType(EbtBool);
1358 break;
1359 case EHTokBool1:
1360 new(&type) TType(EbtBool);
1361 type.makeVector();
1362 break;
John Kessenich87142c72016-03-12 20:24:24 -07001363 case EHTokBool2:
1364 new(&type) TType(EbtBool, EvqTemporary, 2);
1365 break;
1366 case EHTokBool3:
1367 new(&type) TType(EbtBool, EvqTemporary, 3);
1368 break;
1369 case EHTokBool4:
1370 new(&type) TType(EbtBool, EvqTemporary, 4);
1371 break;
1372
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001373 case EHTokHalf:
1374 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1375 break;
1376 case EHTokHalf1:
1377 new(&type) TType(half_bt, EvqTemporary, EpqMedium);
1378 type.makeVector();
1379 break;
1380 case EHTokHalf2:
1381 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 2);
1382 break;
1383 case EHTokHalf3:
1384 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 3);
1385 break;
1386 case EHTokHalf4:
1387 new(&type) TType(half_bt, EvqTemporary, EpqMedium, 4);
1388 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001389
steve-lunarg3226b082016-10-26 19:18:55 -06001390 case EHTokMin16float:
1391 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1392 break;
1393 case EHTokMin16float1:
1394 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium);
1395 type.makeVector();
1396 break;
1397 case EHTokMin16float2:
1398 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 2);
1399 break;
1400 case EHTokMin16float3:
1401 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 3);
1402 break;
1403 case EHTokMin16float4:
1404 new(&type) TType(min16float_bt, EvqTemporary, EpqMedium, 4);
1405 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001406
steve-lunarg3226b082016-10-26 19:18:55 -06001407 case EHTokMin10float:
1408 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1409 break;
1410 case EHTokMin10float1:
1411 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium);
1412 type.makeVector();
1413 break;
1414 case EHTokMin10float2:
1415 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 2);
1416 break;
1417 case EHTokMin10float3:
1418 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 3);
1419 break;
1420 case EHTokMin10float4:
1421 new(&type) TType(min10float_bt, EvqTemporary, EpqMedium, 4);
1422 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001423
steve-lunarg3226b082016-10-26 19:18:55 -06001424 case EHTokMin16int:
1425 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1426 break;
1427 case EHTokMin16int1:
1428 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium);
1429 type.makeVector();
1430 break;
1431 case EHTokMin16int2:
1432 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 2);
1433 break;
1434 case EHTokMin16int3:
1435 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 3);
1436 break;
1437 case EHTokMin16int4:
1438 new(&type) TType(min16int_bt, EvqTemporary, EpqMedium, 4);
1439 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001440
steve-lunarg3226b082016-10-26 19:18:55 -06001441 case EHTokMin12int:
1442 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1443 break;
1444 case EHTokMin12int1:
1445 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium);
1446 type.makeVector();
1447 break;
1448 case EHTokMin12int2:
1449 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 2);
1450 break;
1451 case EHTokMin12int3:
1452 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 3);
1453 break;
1454 case EHTokMin12int4:
1455 new(&type) TType(min12int_bt, EvqTemporary, EpqMedium, 4);
1456 break;
John Kessenichecba76f2017-01-06 00:34:48 -07001457
steve-lunarg3226b082016-10-26 19:18:55 -06001458 case EHTokMin16uint:
1459 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1460 break;
1461 case EHTokMin16uint1:
1462 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium);
1463 type.makeVector();
1464 break;
1465 case EHTokMin16uint2:
1466 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 2);
1467 break;
1468 case EHTokMin16uint3:
1469 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 3);
1470 break;
1471 case EHTokMin16uint4:
1472 new(&type) TType(min16uint_bt, EvqTemporary, EpqMedium, 4);
1473 break;
1474
John Kessenich0133c122016-05-20 12:17:26 -06001475 case EHTokInt1x1:
1476 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
1477 break;
1478 case EHTokInt1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001479 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001480 break;
1481 case EHTokInt1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001482 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001483 break;
1484 case EHTokInt1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001485 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001486 break;
1487 case EHTokInt2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001488 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001489 break;
1490 case EHTokInt2x2:
1491 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
1492 break;
1493 case EHTokInt2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001494 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001495 break;
1496 case EHTokInt2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001497 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001498 break;
1499 case EHTokInt3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001500 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001501 break;
1502 case EHTokInt3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001503 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001504 break;
1505 case EHTokInt3x3:
1506 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
1507 break;
1508 case EHTokInt3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001509 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001510 break;
1511 case EHTokInt4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001512 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001513 break;
1514 case EHTokInt4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001515 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001516 break;
1517 case EHTokInt4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001518 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001519 break;
1520 case EHTokInt4x4:
1521 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1522 break;
1523
John Kessenich71351de2016-06-08 12:50:56 -06001524 case EHTokUint1x1:
1525 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1526 break;
1527 case EHTokUint1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001528 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001529 break;
1530 case EHTokUint1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001531 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001532 break;
1533 case EHTokUint1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001534 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001535 break;
1536 case EHTokUint2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001537 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001538 break;
1539 case EHTokUint2x2:
1540 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1541 break;
1542 case EHTokUint2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001543 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001544 break;
1545 case EHTokUint2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001546 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001547 break;
1548 case EHTokUint3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001549 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001550 break;
1551 case EHTokUint3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001552 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001553 break;
1554 case EHTokUint3x3:
1555 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1556 break;
1557 case EHTokUint3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001558 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001559 break;
1560 case EHTokUint4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001561 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001562 break;
1563 case EHTokUint4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001564 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001565 break;
1566 case EHTokUint4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001567 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001568 break;
1569 case EHTokUint4x4:
1570 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1571 break;
1572
1573 case EHTokBool1x1:
1574 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1575 break;
1576 case EHTokBool1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001577 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001578 break;
1579 case EHTokBool1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001580 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001581 break;
1582 case EHTokBool1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001583 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001584 break;
1585 case EHTokBool2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001586 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001587 break;
1588 case EHTokBool2x2:
1589 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1590 break;
1591 case EHTokBool2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001592 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001593 break;
1594 case EHTokBool2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001595 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001596 break;
1597 case EHTokBool3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001598 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001599 break;
1600 case EHTokBool3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001601 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001602 break;
1603 case EHTokBool3x3:
1604 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1605 break;
1606 case EHTokBool3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001607 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
John Kessenich71351de2016-06-08 12:50:56 -06001608 break;
1609 case EHTokBool4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001610 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
John Kessenich71351de2016-06-08 12:50:56 -06001611 break;
1612 case EHTokBool4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001613 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
John Kessenich71351de2016-06-08 12:50:56 -06001614 break;
1615 case EHTokBool4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001616 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
John Kessenich71351de2016-06-08 12:50:56 -06001617 break;
1618 case EHTokBool4x4:
1619 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1620 break;
1621
John Kessenich0133c122016-05-20 12:17:26 -06001622 case EHTokFloat1x1:
1623 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1624 break;
1625 case EHTokFloat1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001626 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001627 break;
1628 case EHTokFloat1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001629 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001630 break;
1631 case EHTokFloat1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001632 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001633 break;
1634 case EHTokFloat2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001635 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001636 break;
John Kessenich87142c72016-03-12 20:24:24 -07001637 case EHTokFloat2x2:
1638 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1639 break;
1640 case EHTokFloat2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001641 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001642 break;
1643 case EHTokFloat2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001644 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001645 break;
John Kessenich0133c122016-05-20 12:17:26 -06001646 case EHTokFloat3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001647 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001648 break;
John Kessenich87142c72016-03-12 20:24:24 -07001649 case EHTokFloat3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001650 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001651 break;
1652 case EHTokFloat3x3:
1653 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1654 break;
1655 case EHTokFloat3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001656 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
John Kessenich87142c72016-03-12 20:24:24 -07001657 break;
John Kessenich0133c122016-05-20 12:17:26 -06001658 case EHTokFloat4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001659 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001660 break;
John Kessenich87142c72016-03-12 20:24:24 -07001661 case EHTokFloat4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001662 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
John Kessenich87142c72016-03-12 20:24:24 -07001663 break;
1664 case EHTokFloat4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001665 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
John Kessenich87142c72016-03-12 20:24:24 -07001666 break;
1667 case EHTokFloat4x4:
1668 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1669 break;
1670
John Kessenich0133c122016-05-20 12:17:26 -06001671 case EHTokDouble1x1:
1672 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1673 break;
1674 case EHTokDouble1x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001675 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001676 break;
1677 case EHTokDouble1x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001678 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001679 break;
1680 case EHTokDouble1x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001681 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001682 break;
1683 case EHTokDouble2x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001684 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001685 break;
1686 case EHTokDouble2x2:
1687 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1688 break;
1689 case EHTokDouble2x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001690 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001691 break;
1692 case EHTokDouble2x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001693 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001694 break;
1695 case EHTokDouble3x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001696 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001697 break;
1698 case EHTokDouble3x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001699 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001700 break;
1701 case EHTokDouble3x3:
1702 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1703 break;
1704 case EHTokDouble3x4:
steve-lunarg297ae212016-08-24 14:36:13 -06001705 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
John Kessenich0133c122016-05-20 12:17:26 -06001706 break;
1707 case EHTokDouble4x1:
steve-lunarg297ae212016-08-24 14:36:13 -06001708 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
John Kessenich0133c122016-05-20 12:17:26 -06001709 break;
1710 case EHTokDouble4x2:
steve-lunarg297ae212016-08-24 14:36:13 -06001711 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
John Kessenich0133c122016-05-20 12:17:26 -06001712 break;
1713 case EHTokDouble4x3:
steve-lunarg297ae212016-08-24 14:36:13 -06001714 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
John Kessenich0133c122016-05-20 12:17:26 -06001715 break;
1716 case EHTokDouble4x4:
1717 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1718 break;
1719
John Kessenich87142c72016-03-12 20:24:24 -07001720 default:
1721 return false;
1722 }
1723
1724 advanceToken();
1725
1726 return true;
1727}
1728
John Kesseniche6e74942016-06-11 16:43:14 -06001729// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001730// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1731// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1732//
1733// struct_type
1734// : STRUCT
1735// | CBUFFER
1736// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001737//
1738bool HlslGrammar::acceptStruct(TType& type)
1739{
John Kessenichb804de62016-09-05 12:19:18 -06001740 // This storage qualifier will tell us whether it's an AST
1741 // block type or just a generic structure type.
1742 TStorageQualifier storageQualifier = EvqTemporary;
John Kessenich3d157c52016-07-25 16:05:33 -06001743
1744 // CBUFFER
1745 if (acceptTokenClass(EHTokCBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001746 storageQualifier = EvqUniform;
John Kessenich3d157c52016-07-25 16:05:33 -06001747 // TBUFFER
1748 else if (acceptTokenClass(EHTokTBuffer))
John Kessenichb804de62016-09-05 12:19:18 -06001749 storageQualifier = EvqBuffer;
John Kesseniche6e74942016-06-11 16:43:14 -06001750 // STRUCT
John Kessenich3d157c52016-07-25 16:05:33 -06001751 else if (! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001752 return false;
1753
1754 // IDENTIFIER
1755 TString structName = "";
1756 if (peekTokenClass(EHTokIdentifier)) {
1757 structName = *token.string;
1758 advanceToken();
1759 }
1760
John Kessenich3d157c52016-07-25 16:05:33 -06001761 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06001762 TQualifier postDeclQualifier;
1763 postDeclQualifier.clear();
1764 acceptPostDecls(postDeclQualifier);
John Kessenich3d157c52016-07-25 16:05:33 -06001765
John Kesseniche6e74942016-06-11 16:43:14 -06001766 // LEFT_BRACE
1767 if (! acceptTokenClass(EHTokLeftBrace)) {
1768 expected("{");
1769 return false;
1770 }
1771
1772 // struct_declaration_list
1773 TTypeList* typeList;
1774 if (! acceptStructDeclarationList(typeList)) {
1775 expected("struct member declarations");
1776 return false;
1777 }
1778
1779 // RIGHT_BRACE
1780 if (! acceptTokenClass(EHTokRightBrace)) {
1781 expected("}");
1782 return false;
1783 }
1784
1785 // create the user-defined type
John Kessenichb804de62016-09-05 12:19:18 -06001786 if (storageQualifier == EvqTemporary)
John Kessenich3d157c52016-07-25 16:05:33 -06001787 new(&type) TType(typeList, structName);
John Kessenichb804de62016-09-05 12:19:18 -06001788 else {
John Kessenich7735b942016-09-05 12:40:06 -06001789 postDeclQualifier.storage = storageQualifier;
1790 new(&type) TType(typeList, structName, postDeclQualifier); // sets EbtBlock
John Kessenichb804de62016-09-05 12:19:18 -06001791 }
John Kesseniche6e74942016-06-11 16:43:14 -06001792
John Kessenich727b3742017-02-03 17:57:55 -07001793 parseContext.declareStruct(token.loc, structName, type);
John Kesseniche6e74942016-06-11 16:43:14 -06001794
1795 return true;
1796}
1797
steve-lunarg5da1f032017-02-12 17:50:28 -07001798// struct_buffer
1799// : APPENDSTRUCTUREDBUFFER
1800// | BYTEADDRESSBUFFER
1801// | CONSUMESTRUCTUREDBUFFER
1802// | RWBYTEADDRESSBUFFER
1803// | RWSTRUCTUREDBUFFER
1804// | STRUCTUREDBUFFER
1805bool HlslGrammar::acceptStructBufferType(TType& type)
1806{
1807 const EHlslTokenClass structBuffType = peek();
1808
1809 // TODO: globallycoherent
1810 bool hasTemplateType = true;
1811 bool readonly = false;
1812
1813 TStorageQualifier storage = EvqBuffer;
1814
1815 switch (structBuffType) {
1816 case EHTokAppendStructuredBuffer:
1817 unimplemented("AppendStructuredBuffer");
1818 return false;
1819 case EHTokByteAddressBuffer:
1820 hasTemplateType = false;
1821 readonly = true;
1822 break;
1823 case EHTokConsumeStructuredBuffer:
1824 unimplemented("ConsumeStructuredBuffer");
1825 return false;
1826 case EHTokRWByteAddressBuffer:
1827 hasTemplateType = false;
1828 break;
1829 case EHTokRWStructuredBuffer:
1830 break;
1831 case EHTokStructuredBuffer:
1832 readonly = true;
1833 break;
1834 default:
1835 return false; // not a structure buffer type
1836 }
1837
1838 advanceToken(); // consume the structure keyword
1839
1840 // type on which this StructedBuffer is templatized. E.g, StructedBuffer<MyStruct> ==> MyStruct
1841 TType* templateType = new TType;
1842
1843 if (hasTemplateType) {
1844 if (! acceptTokenClass(EHTokLeftAngle)) {
1845 expected("left angle bracket");
1846 return false;
1847 }
1848
1849 if (! acceptType(*templateType)) {
1850 expected("type");
1851 return false;
1852 }
1853 if (! acceptTokenClass(EHTokRightAngle)) {
1854 expected("right angle bracket");
1855 return false;
1856 }
1857 } else {
1858 // byte address buffers have no explicit type.
1859 TType uintType(EbtUint, storage);
1860 templateType->shallowCopy(uintType);
1861 }
1862
1863 // Create an unsized array out of that type.
1864 // TODO: does this work if it's already an array type?
1865 TArraySizes unsizedArray;
1866 unsizedArray.addInnerSize(UnsizedArraySize);
1867 templateType->newArraySizes(unsizedArray);
steve-lunargdd8287a2017-02-23 18:04:12 -07001868
1869 // field name is canonical for all structbuffers
1870 templateType->setFieldName("@data");
steve-lunarg5da1f032017-02-12 17:50:28 -07001871
1872 // Create block type. TODO: hidden internal uint member when needed
steve-lunargdd8287a2017-02-23 18:04:12 -07001873
steve-lunarg5da1f032017-02-12 17:50:28 -07001874 TTypeList* blockStruct = new TTypeList;
1875 TTypeLoc member = { templateType, token.loc };
1876 blockStruct->push_back(member);
1877
steve-lunargdd8287a2017-02-23 18:04:12 -07001878 // This is the type of the buffer block (SSBO)
steve-lunarg5da1f032017-02-12 17:50:28 -07001879 TType blockType(blockStruct, "", templateType->getQualifier());
1880
steve-lunargdd8287a2017-02-23 18:04:12 -07001881 blockType.getQualifier().storage = storage;
1882 blockType.getQualifier().readonly = readonly;
1883
1884 // We may have created an equivalent type before, in which case we should use its
1885 // deep structure.
1886 parseContext.shareStructBufferType(blockType);
1887
steve-lunarg5da1f032017-02-12 17:50:28 -07001888 type.shallowCopy(blockType);
1889
1890 return true;
1891}
1892
John Kesseniche6e74942016-06-11 16:43:14 -06001893// struct_declaration_list
1894// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1895//
1896// struct_declaration
1897// : fully_specified_type struct_declarator COMMA struct_declarator ...
1898//
1899// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001900// : IDENTIFIER post_decls
1901// | IDENTIFIER array_specifier post_decls
John Kesseniche6e74942016-06-11 16:43:14 -06001902//
1903bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
1904{
1905 typeList = new TTypeList();
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001906 HlslToken idToken;
John Kesseniche6e74942016-06-11 16:43:14 -06001907
1908 do {
1909 // success on seeing the RIGHT_BRACE coming up
1910 if (peekTokenClass(EHTokRightBrace))
1911 return true;
1912
1913 // struct_declaration
1914
1915 // fully_specified_type
1916 TType memberType;
1917 if (! acceptFullySpecifiedType(memberType)) {
1918 expected("member type");
1919 return false;
1920 }
1921
1922 // struct_declarator COMMA struct_declarator ...
1923 do {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001924 if (! acceptIdentifier(idToken)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001925 expected("member name");
1926 return false;
1927 }
1928
1929 // add it to the list of members
1930 TTypeLoc member = { new TType(EbtVoid), token.loc };
1931 member.type->shallowCopy(memberType);
steve-lunarg5ca85ad2016-12-26 18:45:52 -07001932 member.type->setFieldName(*idToken.string);
John Kesseniche6e74942016-06-11 16:43:14 -06001933 typeList->push_back(member);
1934
John Kesseniche6e74942016-06-11 16:43:14 -06001935 // array_specifier
John Kessenich19b92ff2016-06-19 11:50:34 -06001936 TArraySizes* arraySizes = nullptr;
1937 acceptArraySpecifier(arraySizes);
1938 if (arraySizes)
1939 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001940
John Kessenich7735b942016-09-05 12:40:06 -06001941 acceptPostDecls(member.type->getQualifier());
John Kessenich630dd7d2016-06-12 23:52:12 -06001942
John Kessenich18adbdb2017-02-02 15:16:20 -07001943 // EQUAL assignment_expression
1944 if (acceptTokenClass(EHTokAssign)) {
1945 parseContext.warn(idToken.loc, "struct-member initializers ignored", "typedef", "");
1946 TIntermTyped* expressionNode = nullptr;
1947 if (! acceptAssignmentExpression(expressionNode)) {
1948 expected("initializer");
1949 return false;
1950 }
1951 }
1952
John Kesseniche6e74942016-06-11 16:43:14 -06001953 // success on seeing the SEMICOLON coming up
1954 if (peekTokenClass(EHTokSemicolon))
1955 break;
1956
1957 // COMMA
1958 if (! acceptTokenClass(EHTokComma)) {
1959 expected(",");
1960 return false;
1961 }
1962
1963 } while (true);
1964
1965 // SEMI_COLON
1966 if (! acceptTokenClass(EHTokSemicolon)) {
1967 expected(";");
1968 return false;
1969 }
1970
1971 } while (true);
1972}
1973
John Kessenich5f934b02016-03-13 17:58:25 -06001974// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06001975// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06001976// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001977//
1978bool HlslGrammar::acceptFunctionParameters(TFunction& function)
1979{
John Kessenich078d7f22016-03-14 10:02:11 -06001980 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001981 if (! acceptTokenClass(EHTokLeftParen))
1982 return false;
1983
John Kessenich71351de2016-06-08 12:50:56 -06001984 // VOID RIGHT_PAREN
1985 if (! acceptTokenClass(EHTokVoid)) {
1986 do {
1987 // parameter_declaration
1988 if (! acceptParameterDeclaration(function))
1989 break;
John Kessenich5f934b02016-03-13 17:58:25 -06001990
John Kessenich71351de2016-06-08 12:50:56 -06001991 // COMMA
1992 if (! acceptTokenClass(EHTokComma))
1993 break;
1994 } while (true);
1995 }
John Kessenich5f934b02016-03-13 17:58:25 -06001996
John Kessenich078d7f22016-03-14 10:02:11 -06001997 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001998 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001999 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06002000 return false;
2001 }
2002
2003 return true;
2004}
2005
steve-lunarg26d31452016-12-23 18:56:57 -07002006// default_parameter_declaration
2007// : EQUAL conditional_expression
2008// : EQUAL initializer
2009bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
2010{
2011 node = nullptr;
2012
2013 // Valid not to have a default_parameter_declaration
2014 if (!acceptTokenClass(EHTokAssign))
2015 return true;
2016
2017 if (!acceptConditionalExpression(node)) {
2018 if (!acceptInitializer(node))
2019 return false;
2020
2021 // For initializer lists, we have to const-fold into a constructor for the type, so build
2022 // that.
2023 TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
2024 if (constructor == nullptr) // cannot construct
2025 return false;
2026
2027 TIntermTyped* arguments = nullptr;
John Kessenichecba76f2017-01-06 00:34:48 -07002028 for (int i = 0; i < int(node->getAsAggregate()->getSequence().size()); i++)
steve-lunarg26d31452016-12-23 18:56:57 -07002029 parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
John Kessenichecba76f2017-01-06 00:34:48 -07002030
steve-lunarg26d31452016-12-23 18:56:57 -07002031 node = parseContext.handleFunctionCall(token.loc, constructor, node);
2032 }
2033
2034 // If this is simply a constant, we can use it directly.
2035 if (node->getAsConstantUnion())
2036 return true;
2037
2038 // Otherwise, it has to be const-foldable.
2039 TIntermTyped* origNode = node;
2040
2041 node = intermediate.fold(node->getAsAggregate());
2042
2043 if (node != nullptr && origNode != node)
2044 return true;
2045
2046 parseContext.error(token.loc, "invalid default parameter value", "", "");
2047
2048 return false;
2049}
2050
John Kessenich5f934b02016-03-13 17:58:25 -06002051// parameter_declaration
steve-lunarg26d31452016-12-23 18:56:57 -07002052// : fully_specified_type post_decls [ = default_parameter_declaration ]
2053// | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
John Kessenich5f934b02016-03-13 17:58:25 -06002054//
2055bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
2056{
2057 // fully_specified_type
2058 TType* type = new TType;
2059 if (! acceptFullySpecifiedType(*type))
2060 return false;
2061
2062 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06002063 HlslToken idToken;
2064 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06002065
John Kessenich19b92ff2016-06-19 11:50:34 -06002066 // array_specifier
2067 TArraySizes* arraySizes = nullptr;
2068 acceptArraySpecifier(arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002069 if (arraySizes) {
2070 if (arraySizes->isImplicit()) {
2071 parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
2072 return false;
2073 }
2074
John Kessenich19b92ff2016-06-19 11:50:34 -06002075 type->newArraySizes(*arraySizes);
steve-lunarg265c0612016-09-27 10:57:35 -06002076 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002077
2078 // post_decls
John Kessenich7735b942016-09-05 12:40:06 -06002079 acceptPostDecls(type->getQualifier());
John Kessenichc3387d32016-06-17 14:21:02 -06002080
steve-lunarg26d31452016-12-23 18:56:57 -07002081 TIntermTyped* defaultValue;
2082 if (!acceptDefaultParameterDeclaration(*type, defaultValue))
2083 return false;
2084
John Kessenich5aa59e22016-06-17 15:50:47 -06002085 parseContext.paramFix(*type);
2086
steve-lunarg26d31452016-12-23 18:56:57 -07002087 // If any prior parameters have default values, all the parameters after that must as well.
2088 if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
2089 parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
2090 return false;
2091 }
2092
2093 TParameter param = { idToken.string, type, defaultValue };
John Kessenich5f934b02016-03-13 17:58:25 -06002094 function.addParameter(param);
2095
2096 return true;
2097}
2098
2099// Do the work to create the function definition in addition to
2100// parsing the body (compound_statement).
John Kessenich02467d82017-01-19 15:41:47 -07002101bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node, TIntermNode*& node2, const TAttributeMap& attributes)
John Kessenich5f934b02016-03-13 17:58:25 -06002102{
John Kessenicha3051662016-09-02 19:13:36 -06002103 TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
John Kessenich1a4b7752016-09-02 19:05:24 -06002104 TSourceLoc loc = token.loc;
John Kessenich5f934b02016-03-13 17:58:25 -06002105
John Kessenich077e0522016-06-09 02:02:17 -06002106 // This does a pushScope()
John Kessenich02467d82017-01-19 15:41:47 -07002107 node = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes, node2);
John Kessenich5f934b02016-03-13 17:58:25 -06002108
2109 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002110 TIntermNode* functionBody = nullptr;
John Kessenich02467d82017-01-19 15:41:47 -07002111 if (! acceptCompoundStatement(functionBody))
2112 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002113
John Kessenich02467d82017-01-19 15:41:47 -07002114 parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, node);
2115
2116 return true;
John Kessenich5f934b02016-03-13 17:58:25 -06002117}
2118
John Kessenich0d2b6de2016-06-05 11:23:11 -06002119// Accept an expression with parenthesis around it, where
2120// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002121// syntactically required ones like in "if ( expression )".
2122//
2123// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06002124//
2125// Note this one is not set up to be speculative; as it gives
2126// errors if not found.
2127//
2128bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
2129{
2130 // LEFT_PAREN
2131 if (! acceptTokenClass(EHTokLeftParen))
2132 expected("(");
2133
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002134 bool decl = false;
2135 TIntermNode* declNode = nullptr;
2136 decl = acceptControlDeclaration(declNode);
2137 if (decl) {
2138 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
2139 expected("initialized declaration");
2140 return false;
2141 } else
2142 expression = declNode->getAsTyped();
2143 } else {
2144 // no declaration
2145 if (! acceptExpression(expression)) {
2146 expected("expression");
2147 return false;
2148 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002149 }
2150
2151 // RIGHT_PAREN
2152 if (! acceptTokenClass(EHTokRightParen))
2153 expected(")");
2154
2155 return true;
2156}
2157
John Kessenich34fb0362016-05-03 23:17:20 -06002158// The top-level full expression recognizer.
2159//
John Kessenich87142c72016-03-12 20:24:24 -07002160// expression
John Kessenich34fb0362016-05-03 23:17:20 -06002161// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07002162//
2163bool HlslGrammar::acceptExpression(TIntermTyped*& node)
2164{
LoopDawgef764a22016-06-03 09:17:51 -06002165 node = nullptr;
2166
John Kessenich34fb0362016-05-03 23:17:20 -06002167 // assignment_expression
2168 if (! acceptAssignmentExpression(node))
2169 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002170
John Kessenich34fb0362016-05-03 23:17:20 -06002171 if (! peekTokenClass(EHTokComma))
2172 return true;
2173
2174 do {
2175 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06002176 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06002177 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06002178
John Kessenich34fb0362016-05-03 23:17:20 -06002179 // ... assignment_expression
2180 TIntermTyped* rightNode = nullptr;
2181 if (! acceptAssignmentExpression(rightNode)) {
2182 expected("assignment expression");
2183 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06002184 }
2185
John Kessenich34fb0362016-05-03 23:17:20 -06002186 node = intermediate.addComma(node, rightNode, loc);
2187
2188 if (! peekTokenClass(EHTokComma))
2189 return true;
2190 } while (true);
2191}
2192
John Kessenich07354242016-07-01 19:58:06 -06002193// initializer
John Kessenich98ad4852016-11-27 17:39:07 -07002194// : LEFT_BRACE RIGHT_BRACE
2195// | LEFT_BRACE initializer_list RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002196//
2197// initializer_list
2198// : assignment_expression COMMA assignment_expression COMMA ...
2199//
2200bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
2201{
2202 // LEFT_BRACE
2203 if (! acceptTokenClass(EHTokLeftBrace))
2204 return false;
2205
John Kessenich98ad4852016-11-27 17:39:07 -07002206 // RIGHT_BRACE
John Kessenich07354242016-07-01 19:58:06 -06002207 TSourceLoc loc = token.loc;
John Kessenich98ad4852016-11-27 17:39:07 -07002208 if (acceptTokenClass(EHTokRightBrace)) {
2209 // a zero-length initializer list
2210 node = intermediate.makeAggregate(loc);
2211 return true;
2212 }
2213
2214 // initializer_list
John Kessenich07354242016-07-01 19:58:06 -06002215 node = nullptr;
2216 do {
2217 // assignment_expression
2218 TIntermTyped* expr;
2219 if (! acceptAssignmentExpression(expr)) {
2220 expected("assignment expression in initializer list");
2221 return false;
2222 }
2223 node = intermediate.growAggregate(node, expr, loc);
2224
2225 // COMMA
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002226 if (acceptTokenClass(EHTokComma)) {
2227 if (acceptTokenClass(EHTokRightBrace)) // allow trailing comma
2228 return true;
John Kessenich07354242016-07-01 19:58:06 -06002229 continue;
steve-lunargfe5a3ff2016-07-30 10:36:09 -06002230 }
John Kessenich07354242016-07-01 19:58:06 -06002231
2232 // RIGHT_BRACE
2233 if (acceptTokenClass(EHTokRightBrace))
2234 return true;
2235
2236 expected(", or }");
2237 return false;
2238 } while (true);
2239}
2240
John Kessenich34fb0362016-05-03 23:17:20 -06002241// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06002242// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06002243//
2244// a op (b op (c op d))
2245//
2246// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06002247// : initializer
2248// | conditional_expression
2249// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06002250//
2251bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
2252{
John Kessenich07354242016-07-01 19:58:06 -06002253 // initializer
2254 if (peekTokenClass(EHTokLeftBrace)) {
2255 if (acceptInitializer(node))
2256 return true;
2257
2258 expected("initializer");
2259 return false;
2260 }
2261
John Kessenich00957f82016-07-27 10:39:57 -06002262 // conditional_expression
2263 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06002264 return false;
2265
John Kessenich07354242016-07-01 19:58:06 -06002266 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06002267 TOperator assignOp = HlslOpMap::assignment(peek());
2268 if (assignOp == EOpNull)
2269 return true;
2270
John Kessenich00957f82016-07-27 10:39:57 -06002271 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06002272 TSourceLoc loc = token.loc;
2273 advanceToken();
2274
John Kessenich00957f82016-07-27 10:39:57 -06002275 // conditional_expression assign_op conditional_expression ...
2276 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06002277 // gets the right-to-left associativity.
2278 TIntermTyped* rightNode = nullptr;
2279 if (! acceptAssignmentExpression(rightNode)) {
2280 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06002281 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002282 }
2283
John Kessenichd21baed2016-09-16 03:05:12 -06002284 node = parseContext.handleAssign(loc, assignOp, node, rightNode);
steve-lunarg90707962016-10-07 19:35:40 -06002285 node = parseContext.handleLvalue(loc, "assign", node);
2286
John Kessenichfea226b2016-07-28 17:53:56 -06002287 if (node == nullptr) {
2288 parseContext.error(loc, "could not create assignment", "", "");
2289 return false;
2290 }
John Kessenich34fb0362016-05-03 23:17:20 -06002291
2292 if (! peekTokenClass(EHTokComma))
2293 return true;
2294
2295 return true;
2296}
2297
John Kessenich00957f82016-07-27 10:39:57 -06002298// Accept a conditional expression, which associates right-to-left,
2299// accomplished by the "true" expression calling down to lower
2300// precedence levels than this level.
2301//
2302// conditional_expression
2303// : binary_expression
2304// | binary_expression QUESTION expression COLON assignment_expression
2305//
2306bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
2307{
2308 // binary_expression
2309 if (! acceptBinaryExpression(node, PlLogicalOr))
2310 return false;
2311
2312 if (! acceptTokenClass(EHTokQuestion))
2313 return true;
2314
2315 TIntermTyped* trueNode = nullptr;
2316 if (! acceptExpression(trueNode)) {
2317 expected("expression after ?");
2318 return false;
2319 }
2320 TSourceLoc loc = token.loc;
2321
2322 if (! acceptTokenClass(EHTokColon)) {
2323 expected(":");
2324 return false;
2325 }
2326
2327 TIntermTyped* falseNode = nullptr;
2328 if (! acceptAssignmentExpression(falseNode)) {
2329 expected("expression after :");
2330 return false;
2331 }
2332
2333 node = intermediate.addSelection(node, trueNode, falseNode, loc);
2334
2335 return true;
2336}
2337
John Kessenich34fb0362016-05-03 23:17:20 -06002338// Accept a binary expression, for binary operations that
2339// associate left-to-right. This is, it is implicit, for example
2340//
2341// ((a op b) op c) op d
2342//
2343// binary_expression
2344// : expression op expression op expression ...
2345//
2346// where 'expression' is the next higher level in precedence.
2347//
2348bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
2349{
2350 if (precedenceLevel > PlMul)
2351 return acceptUnaryExpression(node);
2352
2353 // assignment_expression
2354 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
2355 return false;
2356
John Kessenich34fb0362016-05-03 23:17:20 -06002357 do {
John Kessenich64076ed2016-07-28 21:43:17 -06002358 TOperator op = HlslOpMap::binary(peek());
2359 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
2360 if (tokenLevel < precedenceLevel)
2361 return true;
2362
John Kessenich34fb0362016-05-03 23:17:20 -06002363 // ... op
2364 TSourceLoc loc = token.loc;
2365 advanceToken();
2366
2367 // ... expression
2368 TIntermTyped* rightNode = nullptr;
2369 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
2370 expected("expression");
2371 return false;
2372 }
2373
2374 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06002375 if (node == nullptr) {
2376 parseContext.error(loc, "Could not perform requested binary operation", "", "");
2377 return false;
2378 }
John Kessenich34fb0362016-05-03 23:17:20 -06002379 } while (true);
2380}
2381
2382// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06002383// : (type) unary_expression
2384// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06002385// | - unary_expression
2386// | ! unary_expression
2387// | ~ unary_expression
2388// | ++ unary_expression
2389// | -- unary_expression
2390// | postfix_expression
2391//
2392bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
2393{
John Kessenich1cc1a282016-06-03 16:55:49 -06002394 // (type) unary_expression
2395 // Have to look two steps ahead, because this could be, e.g., a
2396 // postfix_expression instead, since that also starts with at "(".
2397 if (acceptTokenClass(EHTokLeftParen)) {
2398 TType castType;
2399 if (acceptType(castType)) {
steve-lunarg5964c642016-07-30 07:38:55 -06002400 if (acceptTokenClass(EHTokRightParen)) {
2401 // We've matched "(type)" now, get the expression to cast
2402 TSourceLoc loc = token.loc;
2403 if (! acceptUnaryExpression(node))
2404 return false;
2405
2406 // Hook it up like a constructor
2407 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
2408 if (constructorFunction == nullptr) {
2409 expected("type that can be constructed");
2410 return false;
2411 }
2412 TIntermTyped* arguments = nullptr;
2413 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
2414 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
2415
2416 return true;
2417 } else {
2418 // This could be a parenthesized constructor, ala (int(3)), and we just accepted
2419 // the '(int' part. We must back up twice.
2420 recedeToken();
2421 recedeToken();
John Kessenich1cc1a282016-06-03 16:55:49 -06002422 }
John Kessenich1cc1a282016-06-03 16:55:49 -06002423 } else {
2424 // This isn't a type cast, but it still started "(", so if it is a
2425 // unary expression, it can only be a postfix_expression, so try that.
2426 // Back it up first.
2427 recedeToken();
2428 return acceptPostfixExpression(node);
2429 }
2430 }
2431
2432 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06002433 TOperator unaryOp = HlslOpMap::preUnary(peek());
John Kessenichecba76f2017-01-06 00:34:48 -07002434
John Kessenich1cc1a282016-06-03 16:55:49 -06002435 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06002436 if (unaryOp == EOpNull)
2437 return acceptPostfixExpression(node);
2438
2439 // op unary_expression
2440 TSourceLoc loc = token.loc;
2441 advanceToken();
2442 if (! acceptUnaryExpression(node))
2443 return false;
2444
2445 // + is a no-op
2446 if (unaryOp == EOpAdd)
2447 return true;
2448
2449 node = intermediate.addUnaryMath(unaryOp, node, loc);
steve-lunarge5921f12016-10-15 10:29:58 -06002450
2451 // These unary ops require lvalues
2452 if (unaryOp == EOpPreIncrement || unaryOp == EOpPreDecrement)
2453 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002454
2455 return node != nullptr;
2456}
2457
2458// postfix_expression
2459// : LEFT_PAREN expression RIGHT_PAREN
2460// | literal
2461// | constructor
2462// | identifier
2463// | function_call
2464// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
2465// | postfix_expression DOT IDENTIFIER
2466// | postfix_expression INC_OP
2467// | postfix_expression DEC_OP
2468//
2469bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
2470{
2471 // Not implemented as self-recursive:
2472 // The logical "right recursion" is done with an loop at the end
2473
2474 // idToken will pick up either a variable or a function name in a function call
2475 HlslToken idToken;
2476
John Kessenich21472ae2016-06-04 11:46:33 -06002477 // Find something before the postfix operations, as they can't operate
2478 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07002479 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06002480 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002481 if (! acceptExpression(node)) {
2482 expected("expression");
2483 return false;
2484 }
2485 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002486 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002487 return false;
2488 }
John Kessenich34fb0362016-05-03 23:17:20 -06002489 } else if (acceptLiteral(node)) {
John Kessenichecba76f2017-01-06 00:34:48 -07002490 // literal (nothing else to do yet), go on to the
John Kessenich34fb0362016-05-03 23:17:20 -06002491 } else if (acceptConstructor(node)) {
2492 // constructor (nothing else to do yet)
2493 } else if (acceptIdentifier(idToken)) {
2494 // identifier or function_call name
2495 if (! peekTokenClass(EHTokLeftParen)) {
steve-lunarga64ed3e2016-12-18 17:51:14 -07002496 node = parseContext.handleVariable(idToken.loc, idToken.symbol, idToken.string);
John Kessenich34fb0362016-05-03 23:17:20 -06002497 } else if (acceptFunctionCall(idToken, node)) {
2498 // function_call (nothing else to do yet)
2499 } else {
2500 expected("function call arguments");
2501 return false;
2502 }
John Kessenich21472ae2016-06-04 11:46:33 -06002503 } else {
2504 // nothing found, can't post operate
2505 return false;
John Kessenich87142c72016-03-12 20:24:24 -07002506 }
2507
steve-lunarga2b01a02016-11-28 17:09:54 -07002508 // This is to guarantee we do this no matter how we get out of the stack frame.
2509 // This way there's no bug if an early return forgets to do it.
2510 struct tFinalize {
2511 tFinalize(HlslParseContext& p) : parseContext(p) { }
2512 ~tFinalize() { parseContext.finalizeFlattening(); }
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002513 HlslParseContext& parseContext;
John Kessenich32fd5d22017-02-02 14:55:02 -07002514 private:
John Kessenichf8d0d8c2017-02-08 17:31:03 -07002515 const tFinalize& operator=(const tFinalize& f);
2516 tFinalize(const tFinalize& f);
steve-lunarga2b01a02016-11-28 17:09:54 -07002517 } finalize(parseContext);
2518
2519 // Initialize the flattening accumulation data, so we can track data across multiple bracket or
2520 // dot operators. This can also be nested, e.g, for [], so we have to track each nesting
2521 // level: hence the init and finalize. Even though in practice these must be
2522 // constants, they are parsed no matter what.
2523 parseContext.initFlattening();
2524
John Kessenich21472ae2016-06-04 11:46:33 -06002525 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06002526 do {
2527 TSourceLoc loc = token.loc;
2528 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07002529
John Kessenich34fb0362016-05-03 23:17:20 -06002530 // Consume only a valid post-unary operator, otherwise we are done.
2531 switch (postOp) {
2532 case EOpIndexDirectStruct:
2533 case EOpIndexIndirect:
2534 case EOpPostIncrement:
2535 case EOpPostDecrement:
2536 advanceToken();
2537 break;
2538 default:
2539 return true;
2540 }
John Kessenich87142c72016-03-12 20:24:24 -07002541
John Kessenich34fb0362016-05-03 23:17:20 -06002542 // We have a valid post-unary operator, process it.
2543 switch (postOp) {
2544 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06002545 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002546 // DOT IDENTIFIER
2547 // includes swizzles and struct members
John Kessenich93a162a2016-06-17 17:16:27 -06002548 HlslToken field;
2549 if (! acceptIdentifier(field)) {
2550 expected("swizzle or member");
2551 return false;
2552 }
LoopDawg4886f692016-06-29 10:58:58 -06002553
2554 TIntermTyped* base = node; // preserve for method function calls
John Kessenich93a162a2016-06-17 17:16:27 -06002555 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06002556
2557 // In the event of a method node, we look for an open paren and accept the function call.
steve-lunarga2b01a02016-11-28 17:09:54 -07002558 if (node != nullptr && node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) {
LoopDawg4886f692016-06-29 10:58:58 -06002559 if (! acceptFunctionCall(field, node, base)) {
2560 expected("function parameters");
2561 return false;
2562 }
2563 }
2564
John Kessenich34fb0362016-05-03 23:17:20 -06002565 break;
John Kessenich93a162a2016-06-17 17:16:27 -06002566 }
John Kessenich34fb0362016-05-03 23:17:20 -06002567 case EOpIndexIndirect:
2568 {
John Kessenich19b92ff2016-06-19 11:50:34 -06002569 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06002570 TIntermTyped* indexNode = nullptr;
2571 if (! acceptExpression(indexNode) ||
2572 ! peekTokenClass(EHTokRightBracket)) {
2573 expected("expression followed by ']'");
2574 return false;
2575 }
John Kessenich19b92ff2016-06-19 11:50:34 -06002576 advanceToken();
2577 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
2578 break;
John Kessenich34fb0362016-05-03 23:17:20 -06002579 }
2580 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002581 // INC_OP
2582 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06002583 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06002584 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06002585 node = intermediate.addUnaryMath(postOp, node, loc);
steve-lunarg07830e82016-10-10 10:00:14 -06002586 node = parseContext.handleLvalue(loc, "unary operator", node);
John Kessenich34fb0362016-05-03 23:17:20 -06002587 break;
2588 default:
2589 assert(0);
2590 break;
2591 }
2592 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07002593}
2594
John Kessenichd016be12016-03-13 11:24:20 -06002595// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06002596// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06002597//
2598bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
2599{
2600 // type
2601 TType type;
2602 if (acceptType(type)) {
2603 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
2604 if (constructorFunction == nullptr)
2605 return false;
2606
2607 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06002608 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06002609 if (! acceptArguments(constructorFunction, arguments)) {
steve-lunarg5ca85ad2016-12-26 18:45:52 -07002610 // It's possible this is a type keyword used as an identifier. Put the token back
2611 // for later use.
2612 recedeToken();
John Kessenichd016be12016-03-13 11:24:20 -06002613 return false;
2614 }
2615
2616 // hook it up
2617 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
2618
2619 return true;
2620 }
2621
2622 return false;
2623}
2624
John Kessenich34fb0362016-05-03 23:17:20 -06002625// The function_call identifier was already recognized, and passed in as idToken.
2626//
2627// function_call
2628// : [idToken] arguments
2629//
LoopDawg4886f692016-06-29 10:58:58 -06002630bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base)
John Kessenich34fb0362016-05-03 23:17:20 -06002631{
John Kessenich4678ca92016-05-13 09:33:42 -06002632 // arguments
2633 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
2634 TIntermTyped* arguments = nullptr;
LoopDawg4886f692016-06-29 10:58:58 -06002635
2636 // methods have an implicit first argument of the calling object.
2637 if (base != nullptr)
2638 parseContext.handleFunctionArgument(function, arguments, base);
2639
John Kessenich4678ca92016-05-13 09:33:42 -06002640 if (! acceptArguments(function, arguments))
2641 return false;
2642
2643 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
2644
2645 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06002646}
2647
John Kessenich87142c72016-03-12 20:24:24 -07002648// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06002649// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002650//
John Kessenichd016be12016-03-13 11:24:20 -06002651// The arguments are pushed onto the 'function' argument list and
2652// onto the 'arguments' aggregate.
2653//
John Kessenich4678ca92016-05-13 09:33:42 -06002654bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07002655{
John Kessenich078d7f22016-03-14 10:02:11 -06002656 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002657 if (! acceptTokenClass(EHTokLeftParen))
2658 return false;
2659
2660 do {
John Kessenichd016be12016-03-13 11:24:20 -06002661 // expression
John Kessenich87142c72016-03-12 20:24:24 -07002662 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06002663 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07002664 break;
John Kessenichd016be12016-03-13 11:24:20 -06002665
2666 // hook it up
2667 parseContext.handleFunctionArgument(function, arguments, arg);
2668
John Kessenich078d7f22016-03-14 10:02:11 -06002669 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07002670 if (! acceptTokenClass(EHTokComma))
2671 break;
2672 } while (true);
2673
John Kessenich078d7f22016-03-14 10:02:11 -06002674 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07002675 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002676 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07002677 return false;
2678 }
2679
2680 return true;
2681}
2682
2683bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
2684{
2685 switch (token.tokenClass) {
2686 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002687 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002688 break;
steve-lunarg2de32912016-07-28 14:49:48 -06002689 case EHTokUintConstant:
2690 node = intermediate.addConstantUnion(token.u, token.loc, true);
2691 break;
John Kessenich87142c72016-03-12 20:24:24 -07002692 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002693 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002694 break;
2695 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002696 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002697 break;
2698 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06002699 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07002700 break;
John Kessenich86f71382016-09-19 20:23:18 -06002701 case EHTokStringConstant:
steve-lunarg858c9282017-01-07 08:54:10 -07002702 node = intermediate.addConstantUnion(token.string, token.loc, true);
John Kessenich86f71382016-09-19 20:23:18 -06002703 break;
John Kessenich87142c72016-03-12 20:24:24 -07002704
2705 default:
2706 return false;
2707 }
2708
2709 advanceToken();
2710
2711 return true;
2712}
2713
John Kessenich5f934b02016-03-13 17:58:25 -06002714// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002715// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002716//
John Kessenich21472ae2016-06-04 11:46:33 -06002717bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002718{
John Kessenich21472ae2016-06-04 11:46:33 -06002719 TIntermAggregate* compoundStatement = nullptr;
2720
John Kessenich34fb0362016-05-03 23:17:20 -06002721 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002722 if (! acceptTokenClass(EHTokLeftBrace))
2723 return false;
2724
2725 // statement statement ...
2726 TIntermNode* statement = nullptr;
2727 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002728 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2729 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2730 branch->getFlowOp() == EOpDefault)) {
2731 // hook up individual subsequences within a switch statement
2732 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2733 compoundStatement = nullptr;
2734 } else {
2735 // hook it up to the growing compound statement
2736 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2737 }
John Kessenich5f934b02016-03-13 17:58:25 -06002738 }
John Kessenich34fb0362016-05-03 23:17:20 -06002739 if (compoundStatement)
2740 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002741
John Kessenich21472ae2016-06-04 11:46:33 -06002742 retStatement = compoundStatement;
2743
John Kessenich34fb0362016-05-03 23:17:20 -06002744 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002745 return acceptTokenClass(EHTokRightBrace);
2746}
2747
John Kessenich0d2b6de2016-06-05 11:23:11 -06002748bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2749{
2750 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002751 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002752 parseContext.popScope();
2753
2754 return result;
2755}
2756
John Kessenich077e0522016-06-09 02:02:17 -06002757bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002758{
John Kessenich077e0522016-06-09 02:02:17 -06002759 parseContext.pushScope();
2760 bool result = acceptCompoundStatement(statement);
2761 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002762
2763 return result;
2764}
2765
John Kessenich5f934b02016-03-13 17:58:25 -06002766// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002767// : attributes attributed_statement
2768//
2769// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002770// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002771// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002772// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002773// | declaration_statement
2774// | selection_statement
2775// | switch_statement
2776// | case_label
2777// | iteration_statement
2778// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002779//
2780bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2781{
John Kessenich21472ae2016-06-04 11:46:33 -06002782 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002783
John Kessenich21472ae2016-06-04 11:46:33 -06002784 // attributes
steve-lunarg1868b142016-10-20 13:07:10 -06002785 TAttributeMap attributes;
2786 acceptAttributes(attributes);
John Kessenich5f934b02016-03-13 17:58:25 -06002787
John Kessenich21472ae2016-06-04 11:46:33 -06002788 // attributed_statement
2789 switch (peek()) {
2790 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002791 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002792
John Kessenich21472ae2016-06-04 11:46:33 -06002793 case EHTokIf:
2794 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002795
John Kessenich21472ae2016-06-04 11:46:33 -06002796 case EHTokSwitch:
2797 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002798
John Kessenich21472ae2016-06-04 11:46:33 -06002799 case EHTokFor:
2800 case EHTokDo:
2801 case EHTokWhile:
2802 return acceptIterationStatement(statement);
2803
2804 case EHTokContinue:
2805 case EHTokBreak:
2806 case EHTokDiscard:
2807 case EHTokReturn:
2808 return acceptJumpStatement(statement);
2809
2810 case EHTokCase:
2811 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002812 case EHTokDefault:
2813 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002814
2815 case EHTokSemicolon:
2816 return acceptTokenClass(EHTokSemicolon);
2817
2818 case EHTokRightBrace:
2819 // Performance: not strictly necessary, but stops a bunch of hunting early,
2820 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002821 return false;
2822
John Kessenich21472ae2016-06-04 11:46:33 -06002823 default:
2824 {
2825 // declaration
2826 if (acceptDeclaration(statement))
2827 return true;
2828
2829 // expression
2830 TIntermTyped* node;
2831 if (acceptExpression(node))
2832 statement = node;
2833 else
2834 return false;
2835
2836 // SEMICOLON (following an expression)
2837 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002838 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002839 return false;
2840 }
2841 }
2842 }
2843
John Kessenich5f934b02016-03-13 17:58:25 -06002844 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002845}
2846
John Kessenich21472ae2016-06-04 11:46:33 -06002847// attributes
2848// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2849//
2850// attribute:
2851// : UNROLL
2852// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2853// | FASTOPT
2854// | ALLOW_UAV_CONDITION
2855// | BRANCH
2856// | FLATTEN
2857// | FORCECASE
2858// | CALL
steve-lunarg1868b142016-10-20 13:07:10 -06002859// | DOMAIN
2860// | EARLYDEPTHSTENCIL
2861// | INSTANCE
2862// | MAXTESSFACTOR
2863// | OUTPUTCONTROLPOINTS
2864// | OUTPUTTOPOLOGY
2865// | PARTITIONING
2866// | PATCHCONSTANTFUNC
2867// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
John Kessenich21472ae2016-06-04 11:46:33 -06002868//
steve-lunarg1868b142016-10-20 13:07:10 -06002869void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
John Kessenich21472ae2016-06-04 11:46:33 -06002870{
steve-lunarg1868b142016-10-20 13:07:10 -06002871 // For now, accept the [ XXX(X) ] syntax, but drop all but
2872 // numthreads, which is used to set the CS local size.
John Kessenich0d2b6de2016-06-05 11:23:11 -06002873 // TODO: subset to correct set? Pass on?
2874 do {
steve-lunarg1868b142016-10-20 13:07:10 -06002875 HlslToken idToken;
2876
John Kessenich0d2b6de2016-06-05 11:23:11 -06002877 // LEFT_BRACKET?
2878 if (! acceptTokenClass(EHTokLeftBracket))
2879 return;
2880
2881 // attribute
steve-lunarg1868b142016-10-20 13:07:10 -06002882 if (acceptIdentifier(idToken)) {
2883 // 'idToken.string' is the attribute
John Kessenich0d2b6de2016-06-05 11:23:11 -06002884 } else if (! peekTokenClass(EHTokRightBracket)) {
2885 expected("identifier");
2886 advanceToken();
2887 }
2888
steve-lunarga22f7db2016-11-11 08:17:44 -07002889 TIntermAggregate* expressions = nullptr;
steve-lunarg1868b142016-10-20 13:07:10 -06002890
2891 // (x, ...)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002892 if (acceptTokenClass(EHTokLeftParen)) {
steve-lunarga22f7db2016-11-11 08:17:44 -07002893 expressions = new TIntermAggregate;
steve-lunarg1868b142016-10-20 13:07:10 -06002894
John Kessenich0d2b6de2016-06-05 11:23:11 -06002895 TIntermTyped* node;
steve-lunarga22f7db2016-11-11 08:17:44 -07002896 bool expectingExpression = false;
John Kessenichecba76f2017-01-06 00:34:48 -07002897
steve-lunarga22f7db2016-11-11 08:17:44 -07002898 while (acceptAssignmentExpression(node)) {
2899 expectingExpression = false;
2900 expressions->getSequence().push_back(node);
steve-lunarg1868b142016-10-20 13:07:10 -06002901 if (acceptTokenClass(EHTokComma))
steve-lunarga22f7db2016-11-11 08:17:44 -07002902 expectingExpression = true;
steve-lunarg1868b142016-10-20 13:07:10 -06002903 }
2904
steve-lunarga22f7db2016-11-11 08:17:44 -07002905 // 'expressions' is an aggregate with the expressions in it
John Kessenich0d2b6de2016-06-05 11:23:11 -06002906 if (! acceptTokenClass(EHTokRightParen))
2907 expected(")");
steve-lunarga22f7db2016-11-11 08:17:44 -07002908
2909 // Error for partial or missing expression
2910 if (expectingExpression || expressions->getSequence().empty())
2911 expected("expression");
John Kessenich0d2b6de2016-06-05 11:23:11 -06002912 }
2913
2914 // RIGHT_BRACKET
steve-lunarg1868b142016-10-20 13:07:10 -06002915 if (!acceptTokenClass(EHTokRightBracket)) {
2916 expected("]");
2917 return;
2918 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06002919
steve-lunarg1868b142016-10-20 13:07:10 -06002920 // Add any values we found into the attribute map. This accepts
2921 // (and ignores) values not mapping to a known TAttributeType;
steve-lunarga22f7db2016-11-11 08:17:44 -07002922 attributes.setAttribute(idToken.string, expressions);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002923 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06002924}
2925
John Kessenich0d2b6de2016-06-05 11:23:11 -06002926// selection_statement
2927// : IF LEFT_PAREN expression RIGHT_PAREN statement
2928// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
2929//
John Kessenich21472ae2016-06-04 11:46:33 -06002930bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
2931{
John Kessenich0d2b6de2016-06-05 11:23:11 -06002932 TSourceLoc loc = token.loc;
2933
2934 // IF
2935 if (! acceptTokenClass(EHTokIf))
2936 return false;
2937
2938 // so that something declared in the condition is scoped to the lifetimes
2939 // of the then-else statements
2940 parseContext.pushScope();
2941
2942 // LEFT_PAREN expression RIGHT_PAREN
2943 TIntermTyped* condition;
2944 if (! acceptParenExpression(condition))
2945 return false;
2946
2947 // create the child statements
2948 TIntermNodePair thenElse = { nullptr, nullptr };
2949
2950 // then statement
2951 if (! acceptScopedStatement(thenElse.node1)) {
2952 expected("then statement");
2953 return false;
2954 }
2955
2956 // ELSE
2957 if (acceptTokenClass(EHTokElse)) {
2958 // else statement
2959 if (! acceptScopedStatement(thenElse.node2)) {
2960 expected("else statement");
2961 return false;
2962 }
2963 }
2964
2965 // Put the pieces together
2966 statement = intermediate.addSelection(condition, thenElse, loc);
2967 parseContext.popScope();
2968
2969 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002970}
2971
John Kessenichd02dc5d2016-07-01 00:04:11 -06002972// switch_statement
2973// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
2974//
John Kessenich21472ae2016-06-04 11:46:33 -06002975bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
2976{
John Kessenichd02dc5d2016-07-01 00:04:11 -06002977 // SWITCH
2978 TSourceLoc loc = token.loc;
2979 if (! acceptTokenClass(EHTokSwitch))
2980 return false;
2981
2982 // LEFT_PAREN expression RIGHT_PAREN
2983 parseContext.pushScope();
2984 TIntermTyped* switchExpression;
2985 if (! acceptParenExpression(switchExpression)) {
2986 parseContext.popScope();
2987 return false;
2988 }
2989
2990 // compound_statement
2991 parseContext.pushSwitchSequence(new TIntermSequence);
2992 bool statementOkay = acceptCompoundStatement(statement);
2993 if (statementOkay)
2994 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
2995
2996 parseContext.popSwitchSequence();
2997 parseContext.popScope();
2998
2999 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06003000}
3001
John Kessenich119f8f62016-06-05 15:44:07 -06003002// iteration_statement
3003// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
3004// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
3005// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
3006//
3007// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06003008bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
3009{
John Kessenich119f8f62016-06-05 15:44:07 -06003010 TSourceLoc loc = token.loc;
3011 TIntermTyped* condition = nullptr;
3012
3013 EHlslTokenClass loop = peek();
3014 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
3015
3016 // WHILE or DO or FOR
3017 advanceToken();
3018
3019 switch (loop) {
3020 case EHTokWhile:
3021 // so that something declared in the condition is scoped to the lifetime
3022 // of the while sub-statement
3023 parseContext.pushScope();
3024 parseContext.nestLooping();
3025
3026 // LEFT_PAREN condition RIGHT_PAREN
3027 if (! acceptParenExpression(condition))
3028 return false;
3029
3030 // statement
3031 if (! acceptScopedStatement(statement)) {
3032 expected("while sub-statement");
3033 return false;
3034 }
3035
3036 parseContext.unnestLooping();
3037 parseContext.popScope();
3038
3039 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
3040
3041 return true;
3042
3043 case EHTokDo:
3044 parseContext.nestLooping();
3045
3046 if (! acceptTokenClass(EHTokLeftBrace))
3047 expected("{");
3048
3049 // statement
3050 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
3051 expected("do sub-statement");
3052 return false;
3053 }
3054
3055 if (! acceptTokenClass(EHTokRightBrace))
3056 expected("}");
3057
3058 // WHILE
3059 if (! acceptTokenClass(EHTokWhile)) {
3060 expected("while");
3061 return false;
3062 }
3063
3064 // LEFT_PAREN condition RIGHT_PAREN
3065 TIntermTyped* condition;
3066 if (! acceptParenExpression(condition))
3067 return false;
3068
3069 if (! acceptTokenClass(EHTokSemicolon))
3070 expected(";");
3071
3072 parseContext.unnestLooping();
3073
3074 statement = intermediate.addLoop(statement, condition, 0, false, loc);
3075
3076 return true;
3077
3078 case EHTokFor:
3079 {
3080 // LEFT_PAREN
3081 if (! acceptTokenClass(EHTokLeftParen))
3082 expected("(");
3083
3084 // so that something declared in the condition is scoped to the lifetime
3085 // of the for sub-statement
3086 parseContext.pushScope();
3087
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003088 // initializer
3089 TIntermNode* initNode = nullptr;
3090 if (! acceptControlDeclaration(initNode)) {
3091 TIntermTyped* initExpr = nullptr;
3092 acceptExpression(initExpr);
3093 initNode = initExpr;
3094 }
3095 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06003096 if (! acceptTokenClass(EHTokSemicolon))
3097 expected(";");
3098
3099 parseContext.nestLooping();
3100
3101 // condition SEMI_COLON
3102 acceptExpression(condition);
3103 if (! acceptTokenClass(EHTokSemicolon))
3104 expected(";");
3105
3106 // iterator SEMI_COLON
3107 TIntermTyped* iterator = nullptr;
3108 acceptExpression(iterator);
3109 if (! acceptTokenClass(EHTokRightParen))
3110 expected(")");
3111
3112 // statement
3113 if (! acceptScopedStatement(statement)) {
3114 expected("for sub-statement");
3115 return false;
3116 }
3117
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003118 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06003119
3120 parseContext.popScope();
3121 parseContext.unnestLooping();
3122
3123 return true;
3124 }
3125
3126 default:
3127 return false;
3128 }
John Kessenich21472ae2016-06-04 11:46:33 -06003129}
3130
3131// jump_statement
3132// : CONTINUE SEMICOLON
3133// | BREAK SEMICOLON
3134// | DISCARD SEMICOLON
3135// | RETURN SEMICOLON
3136// | RETURN expression SEMICOLON
3137//
3138bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
3139{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003140 EHlslTokenClass jump = peek();
3141 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06003142 case EHTokContinue:
3143 case EHTokBreak:
3144 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06003145 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003146 advanceToken();
3147 break;
John Kessenich21472ae2016-06-04 11:46:33 -06003148 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003149 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06003150 return false;
3151 }
John Kessenich21472ae2016-06-04 11:46:33 -06003152
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003153 switch (jump) {
3154 case EHTokContinue:
3155 statement = intermediate.addBranch(EOpContinue, token.loc);
3156 break;
3157 case EHTokBreak:
3158 statement = intermediate.addBranch(EOpBreak, token.loc);
3159 break;
3160 case EHTokDiscard:
3161 statement = intermediate.addBranch(EOpKill, token.loc);
3162 break;
3163
3164 case EHTokReturn:
3165 {
3166 // expression
3167 TIntermTyped* node;
3168 if (acceptExpression(node)) {
3169 // hook it up
steve-lunargc4a13072016-08-09 11:28:03 -06003170 statement = parseContext.handleReturnValue(token.loc, node);
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003171 } else
3172 statement = intermediate.addBranch(EOpReturn, token.loc);
3173 break;
3174 }
3175
3176 default:
3177 assert(0);
3178 return false;
3179 }
3180
3181 // SEMICOLON
3182 if (! acceptTokenClass(EHTokSemicolon))
3183 expected(";");
John Kessenichecba76f2017-01-06 00:34:48 -07003184
John Kessenich5bc4d9a2016-06-20 01:22:38 -06003185 return true;
3186}
John Kessenich21472ae2016-06-04 11:46:33 -06003187
John Kessenichd02dc5d2016-07-01 00:04:11 -06003188// case_label
3189// : CASE expression COLON
3190//
John Kessenich21472ae2016-06-04 11:46:33 -06003191bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
3192{
John Kessenichd02dc5d2016-07-01 00:04:11 -06003193 TSourceLoc loc = token.loc;
3194 if (! acceptTokenClass(EHTokCase))
3195 return false;
3196
3197 TIntermTyped* expression;
3198 if (! acceptExpression(expression)) {
3199 expected("case expression");
3200 return false;
3201 }
3202
3203 if (! acceptTokenClass(EHTokColon)) {
3204 expected(":");
3205 return false;
3206 }
3207
3208 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
3209
3210 return true;
3211}
3212
3213// default_label
3214// : DEFAULT COLON
3215//
3216bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
3217{
3218 TSourceLoc loc = token.loc;
3219 if (! acceptTokenClass(EHTokDefault))
3220 return false;
3221
3222 if (! acceptTokenClass(EHTokColon)) {
3223 expected(":");
3224 return false;
3225 }
3226
3227 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
3228
3229 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06003230}
3231
John Kessenich19b92ff2016-06-19 11:50:34 -06003232// array_specifier
steve-lunarg7b211a32016-10-13 12:26:18 -06003233// : LEFT_BRACKET integer_expression RGHT_BRACKET ... // optional
3234// : LEFT_BRACKET RGHT_BRACKET // optional
John Kessenich19b92ff2016-06-19 11:50:34 -06003235//
3236void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
3237{
3238 arraySizes = nullptr;
3239
steve-lunarg7b211a32016-10-13 12:26:18 -06003240 // Early-out if there aren't any array dimensions
3241 if (!peekTokenClass(EHTokLeftBracket))
John Kessenich19b92ff2016-06-19 11:50:34 -06003242 return;
3243
steve-lunarg7b211a32016-10-13 12:26:18 -06003244 // 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 -06003245 arraySizes = new TArraySizes;
steve-lunarg7b211a32016-10-13 12:26:18 -06003246
3247 // Collect each array dimension.
3248 while (acceptTokenClass(EHTokLeftBracket)) {
3249 TSourceLoc loc = token.loc;
3250 TIntermTyped* sizeExpr = nullptr;
3251
3252 // Array sizing expression is optional. If ommitted, array will be later sized by initializer list.
3253 const bool hasArraySize = acceptAssignmentExpression(sizeExpr);
3254
3255 if (! acceptTokenClass(EHTokRightBracket)) {
3256 expected("]");
3257 return;
3258 }
3259
3260 if (hasArraySize) {
3261 TArraySize arraySize;
3262 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
3263 arraySizes->addInnerSize(arraySize);
3264 } else {
3265 arraySizes->addInnerSize(0); // sized by initializers.
3266 }
steve-lunarg265c0612016-09-27 10:57:35 -06003267 }
John Kessenich19b92ff2016-06-19 11:50:34 -06003268}
3269
John Kessenich630dd7d2016-06-12 23:52:12 -06003270// post_decls
John Kessenichcfd7ce82016-09-05 16:03:12 -06003271// : COLON semantic // optional
3272// COLON PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN // optional
3273// COLON REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN // optional
John Kesseniche3218e22016-09-05 14:37:03 -06003274// COLON LAYOUT layout_qualifier_list
John Kessenichcfd7ce82016-09-05 16:03:12 -06003275// annotations // optional
John Kessenich630dd7d2016-06-12 23:52:12 -06003276//
John Kessenich7735b942016-09-05 12:40:06 -06003277void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
John Kessenich078d7f22016-03-14 10:02:11 -06003278{
John Kessenich630dd7d2016-06-12 23:52:12 -06003279 do {
John Kessenichecba76f2017-01-06 00:34:48 -07003280 // COLON
John Kessenich630dd7d2016-06-12 23:52:12 -06003281 if (acceptTokenClass(EHTokColon)) {
3282 HlslToken idToken;
John Kesseniche3218e22016-09-05 14:37:03 -06003283 if (peekTokenClass(EHTokLayout))
3284 acceptLayoutQualifierList(qualifier);
3285 else if (acceptTokenClass(EHTokPackOffset)) {
John Kessenich96e9f472016-07-29 14:28:39 -06003286 // PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003287 if (! acceptTokenClass(EHTokLeftParen)) {
3288 expected("(");
3289 return;
3290 }
John Kessenich82d6baf2016-07-29 13:03:05 -06003291 HlslToken locationToken;
3292 if (! acceptIdentifier(locationToken)) {
3293 expected("c[subcomponent][.component]");
3294 return;
3295 }
3296 HlslToken componentToken;
3297 if (acceptTokenClass(EHTokDot)) {
3298 if (! acceptIdentifier(componentToken)) {
3299 expected("component");
3300 return;
3301 }
3302 }
John Kessenich630dd7d2016-06-12 23:52:12 -06003303 if (! acceptTokenClass(EHTokRightParen)) {
3304 expected(")");
3305 break;
3306 }
John Kessenich7735b942016-09-05 12:40:06 -06003307 parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003308 } else if (! acceptIdentifier(idToken)) {
John Kesseniche3218e22016-09-05 14:37:03 -06003309 expected("layout, semantic, packoffset, or register");
John Kessenich630dd7d2016-06-12 23:52:12 -06003310 return;
3311 } else if (*idToken.string == "register") {
John Kessenichcfd7ce82016-09-05 16:03:12 -06003312 // REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
3313 // LEFT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003314 if (! acceptTokenClass(EHTokLeftParen)) {
3315 expected("(");
3316 return;
3317 }
John Kessenichb38f0712016-07-30 10:29:54 -06003318 HlslToken registerDesc; // for Type#
3319 HlslToken profile;
John Kessenich96e9f472016-07-29 14:28:39 -06003320 if (! acceptIdentifier(registerDesc)) {
3321 expected("register number description");
3322 return;
3323 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003324 if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
3325 acceptTokenClass(EHTokComma)) {
John Kessenichb38f0712016-07-30 10:29:54 -06003326 // Then we didn't really see the registerDesc yet, it was
3327 // actually the profile. Adjust...
John Kessenich96e9f472016-07-29 14:28:39 -06003328 profile = registerDesc;
3329 if (! acceptIdentifier(registerDesc)) {
3330 expected("register number description");
3331 return;
3332 }
3333 }
John Kessenichb38f0712016-07-30 10:29:54 -06003334 int subComponent = 0;
3335 if (acceptTokenClass(EHTokLeftBracket)) {
3336 // LEFT_BRACKET subcomponent RIGHT_BRACKET
3337 if (! peekTokenClass(EHTokIntConstant)) {
3338 expected("literal integer");
3339 return;
3340 }
3341 subComponent = token.i;
3342 advanceToken();
3343 if (! acceptTokenClass(EHTokRightBracket)) {
3344 expected("]");
3345 break;
3346 }
3347 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003348 // (COMMA SPACEN)opt
3349 HlslToken spaceDesc;
3350 if (acceptTokenClass(EHTokComma)) {
3351 if (! acceptIdentifier(spaceDesc)) {
3352 expected ("space identifier");
3353 return;
3354 }
3355 }
3356 // RIGHT_PAREN
John Kessenich630dd7d2016-06-12 23:52:12 -06003357 if (! acceptTokenClass(EHTokRightParen)) {
3358 expected(")");
3359 break;
3360 }
John Kessenichcfd7ce82016-09-05 16:03:12 -06003361 parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003362 } else {
3363 // semantic, in idToken.string
John Kessenich7735b942016-09-05 12:40:06 -06003364 parseContext.handleSemantic(idToken.loc, qualifier, *idToken.string);
John Kessenich630dd7d2016-06-12 23:52:12 -06003365 }
John Kessenicha1e2d492016-09-20 13:22:58 -06003366 } else if (peekTokenClass(EHTokLeftAngle))
3367 acceptAnnotations(qualifier);
3368 else
John Kessenich630dd7d2016-06-12 23:52:12 -06003369 break;
John Kessenich078d7f22016-03-14 10:02:11 -06003370
John Kessenich630dd7d2016-06-12 23:52:12 -06003371 } while (true);
John Kessenich078d7f22016-03-14 10:02:11 -06003372}
3373
John Kesseniche01a9bc2016-03-12 20:11:22 -07003374} // end namespace glslang