Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/reshadefx/src/effect_parser_exp.cpp
4246 views
1
/*
2
* Copyright (C) 2014 Patrick Mours
3
* SPDX-License-Identifier: BSD-3-Clause
4
*/
5
6
#include "effect_lexer.hpp"
7
#include "effect_parser.hpp"
8
#include "effect_codegen.hpp"
9
#include <cassert>
10
#include <iterator> // std::back_inserter
11
#include <algorithm> // std::lower_bound, std::set_union
12
13
#define RESHADEFX_SHORT_CIRCUIT 0
14
15
reshadefx::parser::parser()
16
{
17
}
18
reshadefx::parser::~parser()
19
{
20
}
21
22
void reshadefx::parser::error(const location &location, unsigned int code, const std::string &message)
23
{
24
_errors += location.source;
25
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
26
_errors += ": error";
27
if (code != 0)
28
_errors += " X" + std::to_string(code);
29
_errors += ": ";
30
_errors += message;
31
_errors += '\n';
32
}
33
void reshadefx::parser::warning(const location &location, unsigned int code, const std::string &message)
34
{
35
_errors += location.source;
36
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
37
_errors += ": warning";
38
if (code != 0)
39
_errors += " X" + std::to_string(code);
40
_errors += ": ";
41
_errors += message;
42
_errors += '\n';
43
}
44
45
void reshadefx::parser::backup()
46
{
47
_token_backup = _token_next;
48
}
49
void reshadefx::parser::restore()
50
{
51
_lexer->reset_to_offset(_token_backup.offset + _token_backup.length);
52
_token_next = _token_backup; // Copy instead of move here, since restore may be called twice (from 'accept_type_class' and then again from 'parse_expression_unary')
53
}
54
55
void reshadefx::parser::consume()
56
{
57
_token = std::move(_token_next);
58
_token_next = _lexer->lex();
59
}
60
void reshadefx::parser::consume_until(tokenid tokid)
61
{
62
while (!accept(tokid) && !peek(tokenid::end_of_file))
63
{
64
consume();
65
}
66
}
67
68
bool reshadefx::parser::accept(tokenid tokid)
69
{
70
if (peek(tokid))
71
{
72
consume();
73
return true;
74
}
75
76
return false;
77
}
78
bool reshadefx::parser::expect(tokenid tokid)
79
{
80
if (!accept(tokid))
81
{
82
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + "', expected '" + token::id_to_name(tokid) + '\'');
83
return false;
84
}
85
86
return true;
87
}
88
89
bool reshadefx::parser::accept_symbol(std::string &identifier, scoped_symbol &symbol)
90
{
91
// Starting an identifier with '::' restricts the symbol search to the global namespace level
92
const bool exclusive = accept(tokenid::colon_colon);
93
94
if (exclusive ? !expect(tokenid::identifier) : !accept(tokenid::identifier))
95
{
96
// No token should come through here, since all possible prefix expressions should have been handled above, so this is an error in the syntax
97
if (!exclusive)
98
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + '\'');
99
return false;
100
}
101
102
identifier = std::move(_token.literal_as_string);
103
104
// Can concatenate multiple '::' to force symbol search for a specific namespace level
105
while (accept(tokenid::colon_colon))
106
{
107
if (!expect(tokenid::identifier))
108
return false;
109
identifier += "::" + std::move(_token.literal_as_string);
110
}
111
112
// Figure out which scope to start searching in
113
scope scope = { "::", 0, 0 };
114
if (!exclusive)
115
scope = current_scope();
116
117
// Lookup name in the symbol table
118
symbol = find_symbol(identifier, scope, exclusive);
119
120
return true;
121
}
122
bool reshadefx::parser::accept_type_class(type &type)
123
{
124
type.rows = type.cols = 0;
125
126
if (peek(tokenid::identifier) || peek(tokenid::colon_colon))
127
{
128
type.base = type::t_struct;
129
130
backup(); // Need to restore if this identifier does not turn out to be a structure
131
132
std::string identifier;
133
scoped_symbol symbol;
134
if (accept_symbol(identifier, symbol))
135
{
136
if (symbol.id && symbol.op == symbol_type::structure)
137
{
138
type.struct_definition = symbol.id;
139
return true;
140
}
141
}
142
143
restore();
144
145
return false;
146
}
147
148
if (accept(tokenid::vector))
149
{
150
type.base = type::t_float; // Default to float4 unless a type is specified (see below)
151
type.rows = 4, type.cols = 1;
152
153
if (accept('<'))
154
{
155
if (!accept_type_class(type)) // This overwrites the base type again
156
{
157
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + "', expected vector element type");
158
return false;
159
}
160
else if (!type.is_scalar())
161
{
162
error(_token.location, 3122, "vector element type must be a scalar type");
163
return false;
164
}
165
166
if (!expect(',') || !expect(tokenid::int_literal))
167
{
168
return false;
169
}
170
else if (_token.literal_as_int < 1 || _token.literal_as_int > 4)
171
{
172
error(_token.location, 3052, "vector dimension must be between 1 and 4");
173
return false;
174
}
175
176
type.rows = static_cast<unsigned int>(_token.literal_as_int);
177
178
if (!expect('>'))
179
return false;
180
}
181
182
return true;
183
}
184
if (accept(tokenid::matrix))
185
{
186
type.base = type::t_float; // Default to float4x4 unless a type is specified (see below)
187
type.rows = 4, type.cols = 4;
188
189
if (accept('<'))
190
{
191
if (!accept_type_class(type)) // This overwrites the base type again
192
{
193
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + "', expected matrix element type");
194
return false;
195
}
196
else if (!type.is_scalar())
197
{
198
error(_token.location, 3123, "matrix element type must be a scalar type");
199
return false;
200
}
201
202
if (!expect(',') || !expect(tokenid::int_literal))
203
{
204
return false;
205
}
206
else if (_token.literal_as_int < 1 || _token.literal_as_int > 4)
207
{
208
error(_token.location, 3053, "matrix dimensions must be between 1 and 4");
209
return false;
210
}
211
212
type.rows = static_cast<unsigned int>(_token.literal_as_int);
213
214
if (!expect(',') || !expect(tokenid::int_literal))
215
{
216
return false;
217
}
218
else if (_token.literal_as_int < 1 || _token.literal_as_int > 4)
219
{
220
error(_token.location, 3053, "matrix dimensions must be between 1 and 4");
221
return false;
222
}
223
224
type.cols = static_cast<unsigned int>(_token.literal_as_int);
225
226
if (!expect('>'))
227
return false;
228
}
229
230
return true;
231
}
232
233
if (accept(tokenid::sampler1d) || accept(tokenid::sampler2d) || accept(tokenid::sampler3d))
234
{
235
const unsigned int texture_dimension = static_cast<unsigned int>(_token.id) - static_cast<unsigned int>(tokenid::sampler1d);
236
237
if (accept('<'))
238
{
239
if (!accept_type_class(type))
240
{
241
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + "', expected sampler element type");
242
return false;
243
}
244
if (type.is_object())
245
{
246
error(_token.location, 3124, "object element type cannot be an object type");
247
return false;
248
}
249
if (!type.is_numeric() || type.is_matrix())
250
{
251
error(_token.location, 3521, "sampler element type must fit in four 32-bit quantities");
252
return false;
253
}
254
255
if (type.is_integral() && type.is_signed())
256
type.base = static_cast<type::datatype>(type::t_sampler1d_int + texture_dimension);
257
else if (type.is_integral() && type.is_unsigned())
258
type.base = static_cast<type::datatype>(type::t_sampler1d_uint + texture_dimension);
259
else
260
type.base = static_cast<type::datatype>(type::t_sampler1d_float + texture_dimension);
261
262
if (!expect('>'))
263
return false;
264
}
265
else
266
{
267
type.base = static_cast<type::datatype>(type::t_sampler1d_float + texture_dimension);
268
type.rows = 4;
269
type.cols = 1;
270
}
271
272
return true;
273
}
274
if (accept(tokenid::storage1d) || accept(tokenid::storage2d) || accept(tokenid::storage3d))
275
{
276
const unsigned int texture_dimension = static_cast<unsigned int>(_token.id) - static_cast<unsigned int>(tokenid::storage1d);
277
278
if (accept('<'))
279
{
280
if (!accept_type_class(type))
281
{
282
error(_token_next.location, 3000, "syntax error: unexpected '" + token::id_to_name(_token_next.id) + "', expected storage element type");
283
return false;
284
}
285
if (type.is_object())
286
{
287
error(_token.location, 3124, "object element type cannot be an object type");
288
return false;
289
}
290
if (!type.is_numeric() || type.is_matrix())
291
{
292
error(_token.location, 3521, "storage element type must fit in four 32-bit quantities");
293
return false;
294
}
295
296
if (type.is_integral() && type.is_signed())
297
type.base = static_cast<type::datatype>(type::t_storage1d_int + texture_dimension);
298
else if (type.is_integral() && type.is_unsigned())
299
type.base = static_cast<type::datatype>(type::t_storage1d_uint + texture_dimension);
300
else
301
type.base = static_cast<type::datatype>(type::t_storage1d_float + texture_dimension);
302
303
if (!expect('>'))
304
return false;
305
}
306
else
307
{
308
type.base = static_cast<type::datatype>(type::t_storage1d_float + texture_dimension);
309
type.rows = 4;
310
type.cols = 1;
311
}
312
313
return true;
314
}
315
316
switch (_token_next.id)
317
{
318
case tokenid::void_:
319
type.base = type::t_void;
320
break;
321
case tokenid::bool_:
322
case tokenid::bool2:
323
case tokenid::bool3:
324
case tokenid::bool4:
325
type.base = type::t_bool;
326
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::bool_));
327
type.cols = 1;
328
break;
329
case tokenid::bool2x2:
330
case tokenid::bool2x3:
331
case tokenid::bool2x4:
332
case tokenid::bool3x2:
333
case tokenid::bool3x3:
334
case tokenid::bool3x4:
335
case tokenid::bool4x2:
336
case tokenid::bool4x3:
337
case tokenid::bool4x4:
338
type.base = type::t_bool;
339
type.rows = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::bool2x2)) / 3;
340
type.cols = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::bool2x2)) % 3;
341
break;
342
case tokenid::int_:
343
case tokenid::int2:
344
case tokenid::int3:
345
case tokenid::int4:
346
type.base = type::t_int;
347
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::int_));
348
type.cols = 1;
349
break;
350
case tokenid::int2x2:
351
case tokenid::int2x3:
352
case tokenid::int2x4:
353
case tokenid::int3x2:
354
case tokenid::int3x3:
355
case tokenid::int3x4:
356
case tokenid::int4x2:
357
case tokenid::int4x3:
358
case tokenid::int4x4:
359
type.base = type::t_int;
360
type.rows = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::int2x2)) / 3;
361
type.cols = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::int2x2)) % 3;
362
break;
363
case tokenid::min16int:
364
case tokenid::min16int2:
365
case tokenid::min16int3:
366
case tokenid::min16int4:
367
type.base = type::t_min16int;
368
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::min16int));
369
type.cols = 1;
370
break;
371
case tokenid::uint_:
372
case tokenid::uint2:
373
case tokenid::uint3:
374
case tokenid::uint4:
375
type.base = type::t_uint;
376
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::uint_));
377
type.cols = 1;
378
break;
379
case tokenid::uint2x2:
380
case tokenid::uint2x3:
381
case tokenid::uint2x4:
382
case tokenid::uint3x2:
383
case tokenid::uint3x3:
384
case tokenid::uint3x4:
385
case tokenid::uint4x2:
386
case tokenid::uint4x3:
387
case tokenid::uint4x4:
388
type.base = type::t_uint;
389
type.rows = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::uint2x2)) / 3;
390
type.cols = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::uint2x2)) % 3;
391
break;
392
case tokenid::min16uint:
393
case tokenid::min16uint2:
394
case tokenid::min16uint3:
395
case tokenid::min16uint4:
396
type.base = type::t_min16uint;
397
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::min16uint));
398
type.cols = 1;
399
break;
400
case tokenid::float_:
401
case tokenid::float2:
402
case tokenid::float3:
403
case tokenid::float4:
404
type.base = type::t_float;
405
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::float_));
406
type.cols = 1;
407
break;
408
case tokenid::float2x2:
409
case tokenid::float2x3:
410
case tokenid::float2x4:
411
case tokenid::float3x2:
412
case tokenid::float3x3:
413
case tokenid::float3x4:
414
case tokenid::float4x2:
415
case tokenid::float4x3:
416
case tokenid::float4x4:
417
type.base = type::t_float;
418
type.rows = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::float2x2)) / 3;
419
type.cols = 2 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::float2x2)) % 3;
420
break;
421
case tokenid::min16float:
422
case tokenid::min16float2:
423
case tokenid::min16float3:
424
case tokenid::min16float4:
425
type.base = type::t_min16float;
426
type.rows = 1 + (static_cast<unsigned int>(_token_next.id) - static_cast<unsigned int>(tokenid::min16float));
427
type.cols = 1;
428
break;
429
case tokenid::string_:
430
type.base = type::t_string;
431
break;
432
case tokenid::texture1d:
433
type.base = type::t_texture1d;
434
break;
435
case tokenid::texture2d:
436
type.base = type::t_texture2d;
437
break;
438
case tokenid::texture3d:
439
type.base = type::t_texture3d;
440
break;
441
default:
442
return false;
443
}
444
445
consume();
446
447
return true;
448
}
449
bool reshadefx::parser::accept_type_qualifiers(type &type)
450
{
451
unsigned int qualifiers = 0;
452
453
// Storage
454
if (accept(tokenid::extern_))
455
qualifiers |= type::q_extern;
456
if (accept(tokenid::static_))
457
qualifiers |= type::q_static;
458
if (accept(tokenid::uniform_))
459
qualifiers |= type::q_uniform;
460
if (accept(tokenid::volatile_))
461
qualifiers |= type::q_volatile;
462
if (accept(tokenid::precise))
463
qualifiers |= type::q_precise;
464
if (accept(tokenid::groupshared))
465
qualifiers |= type::q_groupshared;
466
467
if (accept(tokenid::in))
468
qualifiers |= type::q_in;
469
if (accept(tokenid::out))
470
qualifiers |= type::q_out;
471
if (accept(tokenid::inout))
472
qualifiers |= type::q_inout;
473
474
// Modifiers
475
if (accept(tokenid::const_))
476
qualifiers |= type::q_const;
477
478
// Interpolation
479
if (accept(tokenid::linear))
480
qualifiers |= type::q_linear;
481
if (accept(tokenid::noperspective))
482
qualifiers |= type::q_noperspective;
483
if (accept(tokenid::centroid))
484
qualifiers |= type::q_centroid;
485
if (accept(tokenid::nointerpolation))
486
qualifiers |= type::q_nointerpolation;
487
488
if (qualifiers == 0)
489
return false;
490
if ((type.qualifiers & qualifiers) == qualifiers)
491
warning(_token.location, 3048, "duplicate usages specified");
492
493
type.qualifiers |= qualifiers;
494
495
// Continue parsing potential additional qualifiers until no more are found
496
accept_type_qualifiers(type);
497
498
return true;
499
}
500
501
bool reshadefx::parser::accept_unary_op()
502
{
503
switch (_token_next.id)
504
{
505
case tokenid::exclaim: // !x (logical not)
506
case tokenid::plus: // +x
507
case tokenid::minus: // -x (negate)
508
case tokenid::tilde: // ~x (bitwise not)
509
case tokenid::plus_plus: // ++x
510
case tokenid::minus_minus: // --x
511
break;
512
default:
513
return false;
514
}
515
516
consume();
517
518
return true;
519
}
520
bool reshadefx::parser::accept_postfix_op()
521
{
522
switch (_token_next.id)
523
{
524
case tokenid::plus_plus: // ++x
525
case tokenid::minus_minus: // --x
526
break;
527
default:
528
return false;
529
}
530
531
consume();
532
533
return true;
534
}
535
bool reshadefx::parser::peek_multary_op(unsigned int &precedence) const
536
{
537
// Precedence values taken from https://cppreference.com/w/cpp/language/operator_precedence
538
switch (_token_next.id)
539
{
540
case tokenid::question: precedence = 1; break; // x ? a : b
541
case tokenid::pipe_pipe: precedence = 2; break; // a || b (logical or)
542
case tokenid::ampersand_ampersand: precedence = 3; break; // a && b (logical and)
543
case tokenid::pipe: precedence = 4; break; // a | b (bitwise or)
544
case tokenid::caret: precedence = 5; break; // a ^ b (bitwise xor)
545
case tokenid::ampersand: precedence = 6; break; // a & b (bitwise and)
546
case tokenid::equal_equal: precedence = 7; break; // a == b (equal)
547
case tokenid::exclaim_equal: precedence = 7; break; // a != b (not equal)
548
case tokenid::less: precedence = 8; break; // a < b
549
case tokenid::greater: precedence = 8; break; // a > b
550
case tokenid::less_equal: precedence = 8; break; // a <= b
551
case tokenid::greater_equal: precedence = 8; break; // a >= b
552
case tokenid::less_less: precedence = 9; break; // a << b (left shift)
553
case tokenid::greater_greater: precedence = 9; break; // a >> b (right shift)
554
case tokenid::plus: precedence = 10; break; // a + b (add)
555
case tokenid::minus: precedence = 10; break; // a - b (subtract)
556
case tokenid::star: precedence = 11; break; // a * b (multiply)
557
case tokenid::slash: precedence = 11; break; // a / b (divide)
558
case tokenid::percent: precedence = 11; break; // a % b (modulo)
559
default:
560
return false;
561
}
562
563
// Do not consume token yet since the expression may be skipped due to precedence
564
return true;
565
}
566
bool reshadefx::parser::accept_assignment_op()
567
{
568
switch (_token_next.id)
569
{
570
case tokenid::equal: // a = b
571
case tokenid::percent_equal: // a %= b
572
case tokenid::ampersand_equal: // a &= b
573
case tokenid::star_equal: // a *= b
574
case tokenid::plus_equal: // a += b
575
case tokenid::minus_equal: // a -= b
576
case tokenid::slash_equal: // a /= b
577
case tokenid::less_less_equal: // a <<= b
578
case tokenid::greater_greater_equal: // a >>= b
579
case tokenid::caret_equal: // a ^= b
580
case tokenid::pipe_equal: // a |= b
581
break;
582
default:
583
return false;
584
}
585
586
consume();
587
588
return true;
589
}
590
591
bool reshadefx::parser::parse_expression(expression &exp)
592
{
593
// Parse first expression
594
if (!parse_expression_assignment(exp))
595
return false;
596
597
// Continue parsing if an expression sequence is next (in the form "a, b, c, ...")
598
while (accept(','))
599
{
600
// Overwrite 'exp' since conveniently the last expression in the sequence is the result
601
if (!parse_expression_assignment(exp))
602
return false;
603
}
604
605
return true;
606
}
607
608
bool reshadefx::parser::parse_expression_unary(expression &exp)
609
{
610
location location = _token_next.location;
611
612
// Check if a prefix operator exists
613
if (accept_unary_op())
614
{
615
// Remember the operator token before parsing the expression that follows it
616
const tokenid op = _token.id;
617
618
// Parse the actual expression
619
if (!parse_expression_unary(exp))
620
return false;
621
622
// Unary operators are only valid on basic types
623
if (!exp.type.is_scalar() && !exp.type.is_vector() && !exp.type.is_matrix())
624
{
625
error(exp.location, 3022, "scalar, vector, or matrix expected");
626
return false;
627
}
628
629
// Special handling for the "++" and "--" operators
630
if (op == tokenid::plus_plus || op == tokenid::minus_minus)
631
{
632
if (exp.type.has(type::q_const) || !exp.is_lvalue)
633
{
634
error(location, 3025, "l-value specifies const object");
635
return false;
636
}
637
638
// Create a constant one in the type of the expression
639
const codegen::id constant_one = _codegen->emit_constant(exp.type, 1);
640
641
const codegen::id value = _codegen->emit_load(exp);
642
const codegen::id result = _codegen->emit_binary_op(location, op, exp.type, value, constant_one);
643
644
// The "++" and "--" operands modify the source variable, so store result back into it
645
_codegen->emit_store(exp, result);
646
}
647
else if (op != tokenid::plus) // Ignore "+" operator since it does not actually do anything
648
{
649
// The "~" bitwise operator is only valid on integral types
650
if (op == tokenid::tilde && !exp.type.is_integral())
651
{
652
error(exp.location, 3082, "int or unsigned int type required");
653
return false;
654
}
655
656
// The logical not operator expects a boolean type as input, so perform cast if necessary
657
if (op == tokenid::exclaim && !exp.type.is_boolean())
658
exp.add_cast_operation({ type::t_bool, exp.type.rows, exp.type.cols }); // The result will be boolean as well
659
660
// Constant expressions can be evaluated at compile time
661
if (!exp.evaluate_constant_expression(op))
662
{
663
const codegen::id value = _codegen->emit_load(exp);
664
const codegen::id result = _codegen->emit_unary_op(location, op, exp.type, value);
665
666
exp.reset_to_rvalue(location, result, exp.type);
667
}
668
}
669
}
670
else if (accept('('))
671
{
672
// This backup may get overridden in 'accept_type_class', but should point to the same token still
673
backup();
674
675
// Check if this is a C-style cast expression
676
if (type cast_type = {}; accept_type_class(cast_type))
677
{
678
if (peek('('))
679
{
680
// This is not a C-style cast but a constructor call, so need to roll-back and parse that instead
681
restore();
682
}
683
else if (expect(')'))
684
{
685
// Parse the expression behind cast operator
686
if (!parse_expression_unary(exp))
687
return false;
688
689
// Check if the types already match, in which case there is nothing to do
690
if (exp.type == cast_type)
691
return true;
692
693
// Check if a cast between these types is valid
694
if (!type::rank(exp.type, cast_type))
695
{
696
error(location, 3017, "cannot convert these types (from " + exp.type.description() + " to " + cast_type.description() + ')');
697
return false;
698
}
699
700
exp.add_cast_operation(cast_type);
701
return true;
702
}
703
else
704
{
705
// Type name was not followed by a closing parenthesis
706
return false;
707
}
708
}
709
710
// Parse expression between the parentheses
711
if (!parse_expression(exp) || !expect(')'))
712
return false;
713
}
714
else if (accept('{'))
715
{
716
bool is_constant = true;
717
std::vector<expression> elements;
718
type composite_type = { type::t_void, 1, 1 };
719
720
while (!peek('}'))
721
{
722
// There should be a comma between arguments
723
if (!elements.empty() && !expect(','))
724
{
725
consume_until('}');
726
return false;
727
}
728
729
// Initializer lists might contain a comma at the end, so break out of the loop if nothing follows afterwards
730
if (peek('}'))
731
break;
732
733
expression &element_exp = elements.emplace_back();
734
735
// Parse the argument expression
736
if (!parse_expression_assignment(element_exp))
737
{
738
consume_until('}');
739
return false;
740
}
741
742
if (element_exp.type.is_array())
743
{
744
error(element_exp.location, 3119, "arrays cannot be multi-dimensional");
745
consume_until('}');
746
return false;
747
}
748
if (composite_type.base != type::t_void && element_exp.type.struct_definition != composite_type.struct_definition)
749
{
750
error(element_exp.location, 3017, "cannot convert these types (from " + element_exp.type.description() + " to " + composite_type.description() + ')');
751
consume_until('}');
752
return false;
753
}
754
755
is_constant &= element_exp.is_constant; // Result is only constant if all arguments are constant
756
composite_type = type::merge(composite_type, element_exp.type);
757
}
758
759
// Constant arrays can be constructed at compile time
760
if (is_constant)
761
{
762
constant result = {};
763
for (expression &element_exp : elements)
764
{
765
element_exp.add_cast_operation(composite_type);
766
result.array_data.push_back(element_exp.constant);
767
}
768
769
composite_type.array_length = static_cast<unsigned int>(elements.size());
770
771
exp.reset_to_rvalue_constant(location, std::move(result), composite_type);
772
}
773
else
774
{
775
// Resolve all access chains
776
for (expression &element_exp : elements)
777
{
778
element_exp.add_cast_operation(composite_type);
779
const codegen::id element_value = _codegen->emit_load(element_exp);
780
element_exp.reset_to_rvalue(element_exp.location, element_value, composite_type);
781
}
782
783
composite_type.array_length = static_cast<unsigned int>(elements.size());
784
785
const codegen::id result = _codegen->emit_construct(location, composite_type, elements);
786
exp.reset_to_rvalue(location, result, composite_type);
787
}
788
789
return expect('}');
790
}
791
else if (accept(tokenid::true_literal))
792
{
793
exp.reset_to_rvalue_constant(location, true);
794
}
795
else if (accept(tokenid::false_literal))
796
{
797
exp.reset_to_rvalue_constant(location, false);
798
}
799
else if (accept(tokenid::int_literal))
800
{
801
exp.reset_to_rvalue_constant(location, _token.literal_as_int);
802
}
803
else if (accept(tokenid::uint_literal))
804
{
805
exp.reset_to_rvalue_constant(location, _token.literal_as_uint);
806
}
807
else if (accept(tokenid::float_literal))
808
{
809
exp.reset_to_rvalue_constant(location, _token.literal_as_float);
810
}
811
else if (accept(tokenid::double_literal))
812
{
813
// Convert double literal to float literal for now
814
warning(location, 5000, "double literal truncated to float literal");
815
816
exp.reset_to_rvalue_constant(location, static_cast<float>(_token.literal_as_double));
817
}
818
else if (accept(tokenid::string_literal))
819
{
820
std::string value = std::move(_token.literal_as_string);
821
822
// Multiple string literals in sequence are concatenated into a single string literal
823
while (accept(tokenid::string_literal))
824
value += _token.literal_as_string;
825
826
exp.reset_to_rvalue_constant(location, std::move(value));
827
}
828
else if (type type = {}; accept_type_class(type)) // Check if this is a constructor call expression
829
{
830
if (!expect('('))
831
return false;
832
833
if (!type.is_numeric())
834
{
835
error(location, 3037, "constructors only defined for numeric base types");
836
return false;
837
}
838
839
// Empty constructors do not exist
840
if (accept(')'))
841
{
842
error(location, 3014, "incorrect number of arguments to numeric-type constructor");
843
return false;
844
}
845
846
// Parse entire argument expression list
847
bool is_constant = true;
848
unsigned int num_components = 0;
849
std::vector<expression> arguments;
850
851
while (!peek(')'))
852
{
853
// There should be a comma between arguments
854
if (!arguments.empty() && !expect(','))
855
return false;
856
857
expression &argument_exp = arguments.emplace_back();
858
859
// Parse the argument expression
860
if (!parse_expression_assignment(argument_exp))
861
return false;
862
863
// Constructors are only defined for numeric base types
864
if (!argument_exp.type.is_numeric())
865
{
866
error(argument_exp.location, 3017, "cannot convert non-numeric types");
867
return false;
868
}
869
870
is_constant &= argument_exp.is_constant; // Result is only constant if all arguments are constant
871
num_components += argument_exp.type.components();
872
}
873
874
// The list should be terminated with a parenthesis
875
if (!expect(')'))
876
return false;
877
878
// The total number of argument elements needs to match the number of elements in the result type
879
if (num_components != type.components())
880
{
881
error(location, 3014, "incorrect number of arguments to numeric-type constructor");
882
return false;
883
}
884
885
assert(num_components > 0 && num_components <= 16 && !type.is_array());
886
887
if (is_constant) // Constants can be converted at compile time
888
{
889
constant result = {};
890
unsigned int i = 0;
891
for (expression &argument_exp : arguments)
892
{
893
argument_exp.add_cast_operation({ type.base, argument_exp.type.rows, argument_exp.type.cols });
894
895
for (unsigned int k = 0; k < argument_exp.type.components(); ++k)
896
result.as_uint[i++] = argument_exp.constant.as_uint[k];
897
}
898
899
exp.reset_to_rvalue_constant(location, std::move(result), type);
900
}
901
else if (arguments.size() > 1)
902
{
903
// Flatten all arguments to a list of scalars
904
for (auto it = arguments.begin(); it != arguments.end();)
905
{
906
// Argument is a scalar already, so only need to cast it
907
if (it->type.is_scalar())
908
{
909
expression &argument_exp = *it++;
910
911
struct type scalar_type = argument_exp.type;
912
scalar_type.base = type.base;
913
argument_exp.add_cast_operation(scalar_type);
914
915
argument_exp.reset_to_rvalue(argument_exp.location, _codegen->emit_load(argument_exp), scalar_type);
916
}
917
else
918
{
919
const expression argument_exp = std::move(*it);
920
it = arguments.erase(it);
921
922
// Convert to a scalar value and re-enter the loop in the next iteration (in case a cast is necessary too)
923
for (unsigned int i = argument_exp.type.components(); i > 0; --i)
924
{
925
expression argument_scalar_exp = argument_exp;
926
argument_scalar_exp.add_constant_index_access(i - 1);
927
928
it = arguments.insert(it, argument_scalar_exp);
929
}
930
}
931
}
932
933
const codegen::id result = _codegen->emit_construct(location, type, arguments);
934
935
exp.reset_to_rvalue(location, result, type);
936
}
937
else // A constructor call with a single argument is identical to a cast
938
{
939
assert(!arguments.empty());
940
941
// Reset expression to only argument and add cast to expression access chain
942
exp = std::move(arguments[0]); exp.add_cast_operation(type);
943
}
944
}
945
// At this point only identifiers are left to check and resolve
946
else
947
{
948
std::string identifier;
949
scoped_symbol symbol;
950
if (!accept_symbol(identifier, symbol))
951
return false;
952
953
// Check if this is a function call or variable reference
954
if (accept('('))
955
{
956
// Can only call symbols that are functions, but do not abort yet if no symbol was found since the identifier may reference an intrinsic
957
if (symbol.id && symbol.op != symbol_type::function)
958
{
959
error(location, 3005, "identifier '" + identifier + "' represents a variable, not a function");
960
return false;
961
}
962
963
// Parse entire argument expression list
964
std::vector<expression> arguments;
965
966
while (!peek(')'))
967
{
968
// There should be a comma between arguments
969
if (!arguments.empty() && !expect(','))
970
return false;
971
972
expression &argument_exp = arguments.emplace_back();
973
974
// Parse the argument expression
975
if (!parse_expression_assignment(argument_exp))
976
return false;
977
}
978
979
// The list should be terminated with a parenthesis
980
if (!expect(')'))
981
return false;
982
983
// Function calls can only be made from within functions
984
if (!_codegen->is_in_function())
985
{
986
error(location, 3005, "invalid function call outside of a function");
987
return false;
988
}
989
990
// Try to resolve the call by searching through both function symbols and intrinsics
991
bool undeclared = !symbol.id, ambiguous = false;
992
993
if (!resolve_function_call(identifier, arguments, symbol.scope, symbol, ambiguous))
994
{
995
if (undeclared)
996
error(location, 3004, "undeclared identifier or no matching intrinsic overload for '" + identifier + '\'');
997
else if (ambiguous)
998
error(location, 3067, "ambiguous function call to '" + identifier + '\'');
999
else
1000
error(location, 3013, "no matching function overload for '" + identifier + '\'');
1001
return false;
1002
}
1003
1004
assert(symbol.function != nullptr);
1005
1006
std::vector<expression> parameters(symbol.function->parameter_list.size());
1007
1008
// We need to allocate some temporary variables to pass in and load results from pointer parameters
1009
for (size_t i = 0; i < arguments.size(); ++i)
1010
{
1011
const auto &param_type = symbol.function->parameter_list[i].type;
1012
1013
if (param_type.has(type::q_out) && (!arguments[i].is_lvalue || (arguments[i].type.has(type::q_const) && !arguments[i].type.is_object())))
1014
{
1015
error(arguments[i].location, 3025, "l-value specifies const object for an 'out' parameter");
1016
return false;
1017
}
1018
1019
if (arguments[i].type.components() > param_type.components())
1020
warning(arguments[i].location, 3206, "implicit truncation of vector type");
1021
1022
if (symbol.op == symbol_type::function || param_type.has(type::q_out))
1023
{
1024
if (param_type.is_object() || param_type.has(type::q_groupshared) /* Special case for atomic intrinsics */)
1025
{
1026
if (arguments[i].type != param_type)
1027
{
1028
error(location, 3004, "no matching intrinsic overload for '" + identifier + '\'');
1029
return false;
1030
}
1031
1032
assert(arguments[i].is_lvalue);
1033
1034
// Do not shadow object or pointer parameters to function calls
1035
size_t chain_index = 0;
1036
const codegen::id access_chain = _codegen->emit_access_chain(arguments[i], chain_index);
1037
parameters[i].reset_to_lvalue(arguments[i].location, access_chain, param_type);
1038
assert(chain_index == arguments[i].chain.size());
1039
1040
// This is referencing a l-value, but want to avoid copying below
1041
parameters[i].is_lvalue = false;
1042
}
1043
else
1044
{
1045
// All user-defined functions actually accept pointers as arguments, same applies to intrinsics with 'out' parameters
1046
const codegen::id temp_variable = _codegen->define_variable(arguments[i].location, param_type);
1047
parameters[i].reset_to_lvalue(arguments[i].location, temp_variable, param_type);
1048
}
1049
}
1050
else
1051
{
1052
expression argument_exp = arguments[i];
1053
argument_exp.add_cast_operation(param_type);
1054
const codegen::id argument_value = _codegen->emit_load(argument_exp);
1055
parameters[i].reset_to_rvalue(argument_exp.location, argument_value, param_type);
1056
1057
// Keep track of whether the parameter is a constant for code generation (this makes the expression invalid for all other uses)
1058
parameters[i].is_constant = argument_exp.is_constant;
1059
}
1060
}
1061
1062
// Copy in parameters from the argument access chains to parameter variables
1063
for (size_t i = 0; i < arguments.size(); ++i)
1064
{
1065
// Only do this for pointer parameters as discovered above
1066
if (parameters[i].is_lvalue && parameters[i].type.has(type::q_in) && !parameters[i].type.is_object())
1067
{
1068
expression argument_exp = arguments[i];
1069
argument_exp.add_cast_operation(parameters[i].type);
1070
const codegen::id argument_value = _codegen->emit_load(argument_exp);
1071
_codegen->emit_store(parameters[i], argument_value);
1072
}
1073
}
1074
1075
// Add remaining default arguments
1076
for (size_t i = arguments.size(); i < parameters.size(); ++i)
1077
{
1078
const auto &param = symbol.function->parameter_list[i];
1079
assert(param.has_default_value || !_errors.empty());
1080
1081
const codegen::id argument_value = _codegen->emit_constant(param.type, param.default_value);
1082
parameters[i].reset_to_rvalue(param.location, argument_value, param.type);
1083
1084
// Keep track of whether the parameter is a constant for code generation (this makes the expression invalid for all other uses)
1085
parameters[i].is_constant = true;
1086
}
1087
1088
// Check if the call resolving found an intrinsic or function and invoke the corresponding code
1089
const codegen::id result = (symbol.op == symbol_type::function) ?
1090
_codegen->emit_call(location, symbol.id, symbol.type, parameters) :
1091
_codegen->emit_call_intrinsic(location, symbol.id, symbol.type, parameters);
1092
1093
exp.reset_to_rvalue(location, result, symbol.type);
1094
1095
// Copy out parameters from parameter variables back to the argument access chains
1096
for (size_t i = 0; i < arguments.size(); ++i)
1097
{
1098
// Only do this for pointer parameters as discovered above
1099
if (parameters[i].is_lvalue && parameters[i].type.has(type::q_out) && !parameters[i].type.is_object())
1100
{
1101
expression argument_exp = parameters[i];
1102
argument_exp.add_cast_operation(arguments[i].type);
1103
const codegen::id argument_value = _codegen->emit_load(argument_exp);
1104
_codegen->emit_store(arguments[i], argument_value);
1105
}
1106
}
1107
1108
if (_codegen->_current_function != nullptr && symbol.op == symbol_type::function)
1109
{
1110
// Calling a function makes the caller inherit all sampler and storage object references from the callee
1111
if (!symbol.function->referenced_samplers.empty())
1112
{
1113
std::vector<codegen::id> referenced_samplers;
1114
referenced_samplers.reserve(_codegen->_current_function->referenced_samplers.size() + symbol.function->referenced_samplers.size());
1115
std::set_union(_codegen->_current_function->referenced_samplers.begin(), _codegen->_current_function->referenced_samplers.end(), symbol.function->referenced_samplers.begin(), symbol.function->referenced_samplers.end(), std::back_inserter(referenced_samplers));
1116
_codegen->_current_function->referenced_samplers = std::move(referenced_samplers);
1117
}
1118
if (!symbol.function->referenced_storages.empty())
1119
{
1120
std::vector<codegen::id> referenced_storages;
1121
referenced_storages.reserve(_codegen->_current_function->referenced_storages.size() + symbol.function->referenced_storages.size());
1122
std::set_union(_codegen->_current_function->referenced_storages.begin(), _codegen->_current_function->referenced_storages.end(), symbol.function->referenced_storages.begin(), symbol.function->referenced_storages.end(), std::back_inserter(referenced_storages));
1123
_codegen->_current_function->referenced_storages = std::move(referenced_storages);
1124
}
1125
1126
// Add callee and all its function references to the callers function references
1127
{
1128
std::vector<codegen::id> referenced_functions;
1129
std::set_union(_codegen->_current_function->referenced_functions.begin(), _codegen->_current_function->referenced_functions.end(), symbol.function->referenced_functions.begin(), symbol.function->referenced_functions.end(), std::back_inserter(referenced_functions));
1130
const auto it = std::lower_bound(referenced_functions.begin(), referenced_functions.end(), symbol.id);
1131
if (it == referenced_functions.end() || *it != symbol.id)
1132
referenced_functions.insert(it, symbol.id);
1133
_codegen->_current_function->referenced_functions = std::move(referenced_functions);
1134
}
1135
}
1136
}
1137
else if (symbol.op == symbol_type::invalid)
1138
{
1139
// Show error if no symbol matching the identifier was found
1140
error(location, 3004, "undeclared identifier '" + identifier + '\'');
1141
return false;
1142
}
1143
else if (symbol.op == symbol_type::variable)
1144
{
1145
assert(symbol.id != 0);
1146
// Simply return the pointer to the variable, dereferencing is done on site where necessary
1147
exp.reset_to_lvalue(location, symbol.id, symbol.type);
1148
1149
if (_codegen->_current_function != nullptr &&
1150
symbol.scope.level == symbol.scope.namespace_level &&
1151
// Ignore invalid symbols that were added during error recovery
1152
symbol.id != 0xFFFFFFFF)
1153
{
1154
// Keep track of any global sampler or storage objects referenced in the current function
1155
if (symbol.type.is_sampler())
1156
{
1157
const auto it = std::lower_bound(_codegen->_current_function->referenced_samplers.begin(), _codegen->_current_function->referenced_samplers.end(), symbol.id);
1158
if (it == _codegen->_current_function->referenced_samplers.end() || *it != symbol.id)
1159
_codegen->_current_function->referenced_samplers.insert(it, symbol.id);
1160
}
1161
if (symbol.type.is_storage())
1162
{
1163
const auto it = std::lower_bound(_codegen->_current_function->referenced_storages.begin(), _codegen->_current_function->referenced_storages.end(), symbol.id);
1164
if (it == _codegen->_current_function->referenced_storages.end() || *it != symbol.id)
1165
_codegen->_current_function->referenced_storages.insert(it, symbol.id);
1166
}
1167
}
1168
}
1169
else if (symbol.op == symbol_type::constant)
1170
{
1171
// Constants are loaded into the access chain
1172
exp.reset_to_rvalue_constant(location, symbol.constant, symbol.type);
1173
}
1174
else
1175
{
1176
// Can only reference variables and constants by name, functions need to be called
1177
error(location, 3005, "identifier '" + identifier + "' represents a function, not a variable");
1178
return false;
1179
}
1180
}
1181
1182
while (!peek(tokenid::end_of_file))
1183
{
1184
location = _token_next.location;
1185
1186
// Check if a postfix operator exists
1187
if (accept_postfix_op())
1188
{
1189
// Unary operators are only valid on basic types
1190
if (!exp.type.is_scalar() && !exp.type.is_vector() && !exp.type.is_matrix())
1191
{
1192
error(exp.location, 3022, "scalar, vector, or matrix expected");
1193
return false;
1194
}
1195
if (exp.type.has(type::q_const) || !exp.is_lvalue)
1196
{
1197
error(exp.location, 3025, "l-value specifies const object");
1198
return false;
1199
}
1200
1201
// Create a constant one in the type of the expression
1202
const codegen::id constant_one = _codegen->emit_constant(exp.type, 1);
1203
1204
const codegen::id value = _codegen->emit_load(exp, true);
1205
const codegen::id result = _codegen->emit_binary_op(location, _token.id, exp.type, value, constant_one);
1206
1207
// The "++" and "--" operands modify the source variable, so store result back into it
1208
_codegen->emit_store(exp, result);
1209
1210
// All postfix operators return a r-value rather than a l-value to the variable
1211
exp.reset_to_rvalue(location, value, exp.type);
1212
}
1213
else if (accept('.'))
1214
{
1215
if (!expect(tokenid::identifier))
1216
return false;
1217
1218
location = std::move(_token.location);
1219
const std::string subscript = std::move(_token.literal_as_string);
1220
1221
if (accept('(')) // Methods (function calls on types) are not supported right now
1222
{
1223
if (!exp.type.is_struct() || exp.type.is_array())
1224
error(location, 3087, "object does not have methods");
1225
else
1226
error(location, 3088, "structures do not have methods");
1227
return false;
1228
}
1229
else if (exp.type.is_array()) // Arrays do not have subscripts
1230
{
1231
error(location, 3018, "invalid subscript on array");
1232
return false;
1233
}
1234
else if (exp.type.is_vector())
1235
{
1236
const int length = static_cast<int>(subscript.size());
1237
if (length > 4)
1238
{
1239
error(location, 3018, "invalid subscript '" + subscript + "', swizzle too long");
1240
return false;
1241
}
1242
1243
bool is_const = false;
1244
signed char offsets[4] = { -1, -1, -1, -1 };
1245
enum { xyzw, rgba, stpq } set[4];
1246
1247
for (int i = 0; i < length; ++i)
1248
{
1249
switch (subscript[i])
1250
{
1251
case 'x': offsets[i] = 0, set[i] = xyzw; break;
1252
case 'y': offsets[i] = 1, set[i] = xyzw; break;
1253
case 'z': offsets[i] = 2, set[i] = xyzw; break;
1254
case 'w': offsets[i] = 3, set[i] = xyzw; break;
1255
case 'r': offsets[i] = 0, set[i] = rgba; break;
1256
case 'g': offsets[i] = 1, set[i] = rgba; break;
1257
case 'b': offsets[i] = 2, set[i] = rgba; break;
1258
case 'a': offsets[i] = 3, set[i] = rgba; break;
1259
case 's': offsets[i] = 0, set[i] = stpq; break;
1260
case 't': offsets[i] = 1, set[i] = stpq; break;
1261
case 'p': offsets[i] = 2, set[i] = stpq; break;
1262
case 'q': offsets[i] = 3, set[i] = stpq; break;
1263
default:
1264
error(location, 3018, "invalid subscript '" + subscript + '\'');
1265
return false;
1266
}
1267
1268
if (i > 0 && (set[i] != set[i - 1]))
1269
{
1270
error(location, 3018, "invalid subscript '" + subscript + "', mixed swizzle sets");
1271
return false;
1272
}
1273
if (static_cast<unsigned int>(offsets[i]) >= exp.type.rows)
1274
{
1275
error(location, 3018, "invalid subscript '" + subscript + "', swizzle out of range");
1276
return false;
1277
}
1278
1279
// The result is not modifiable if a swizzle appears multiple times
1280
for (int k = 0; k < i; ++k)
1281
{
1282
if (offsets[k] == offsets[i])
1283
{
1284
is_const = true;
1285
break;
1286
}
1287
}
1288
}
1289
1290
// Add swizzle to current access chain
1291
exp.add_swizzle_access(offsets, static_cast<unsigned int>(length));
1292
1293
if (is_const)
1294
exp.type.qualifiers |= type::q_const;
1295
}
1296
else if (exp.type.is_matrix())
1297
{
1298
const int length = static_cast<int>(subscript.size());
1299
if (length < 3)
1300
{
1301
error(location, 3018, "invalid subscript '" + subscript + '\'');
1302
return false;
1303
}
1304
1305
bool is_const = false;
1306
signed char offsets[4] = { -1, -1, -1, -1 };
1307
const int set = subscript[1] == 'm';
1308
const int coefficient = !set;
1309
1310
for (int i = 0, j = 0; i < length; i += 3 + set, ++j)
1311
{
1312
if (subscript[i] != '_' ||
1313
subscript[i + set + 1] < '0' + coefficient ||
1314
subscript[i + set + 1] > '3' + coefficient ||
1315
subscript[i + set + 2] < '0' + coefficient ||
1316
subscript[i + set + 2] > '3' + coefficient)
1317
{
1318
error(location, 3018, "invalid subscript '" + subscript + '\'');
1319
return false;
1320
}
1321
if (set && subscript[i + 1] != 'm')
1322
{
1323
error(location, 3018, "invalid subscript '" + subscript + "', mixed swizzle sets");
1324
return false;
1325
}
1326
1327
const auto row = static_cast<unsigned int>((subscript[i + set + 1] - '0') - coefficient);
1328
const auto col = static_cast<unsigned int>((subscript[i + set + 2] - '0') - coefficient);
1329
1330
if ((row >= exp.type.rows || col >= exp.type.cols) || j > 3)
1331
{
1332
error(location, 3018, "invalid subscript '" + subscript + "', swizzle out of range");
1333
return false;
1334
}
1335
1336
offsets[j] = static_cast<signed char>(row * 4 + col);
1337
1338
// The result is not modifiable if a swizzle appears multiple times
1339
for (int k = 0; k < j; ++k)
1340
{
1341
if (offsets[k] == offsets[j])
1342
{
1343
is_const = true;
1344
break;
1345
}
1346
}
1347
}
1348
1349
// Add swizzle to current access chain
1350
exp.add_swizzle_access(offsets, static_cast<unsigned int>(length / (3 + set)));
1351
1352
if (is_const)
1353
exp.type.qualifiers |= type::q_const;
1354
}
1355
else if (exp.type.is_struct())
1356
{
1357
const std::vector<member_type> &member_list = _codegen->get_struct(exp.type.struct_definition).member_list;
1358
1359
// Find member with matching name is structure definition
1360
uint32_t member_index = 0;
1361
for (const member_type &member : member_list)
1362
{
1363
if (member.name == subscript)
1364
break;
1365
++member_index;
1366
}
1367
1368
if (member_index >= member_list.size())
1369
{
1370
error(location, 3018, "invalid subscript '" + subscript + '\'');
1371
return false;
1372
}
1373
1374
// Add field index to current access chain
1375
exp.add_member_access(member_index, member_list[member_index].type);
1376
}
1377
else if (exp.type.is_scalar())
1378
{
1379
const int length = static_cast<int>(subscript.size());
1380
if (length > 4)
1381
{
1382
error(location, 3018, "invalid subscript '" + subscript + "', swizzle too long");
1383
return false;
1384
}
1385
1386
for (int i = 0; i < length; ++i)
1387
{
1388
if ((subscript[i] != 'x' && subscript[i] != 'r' && subscript[i] != 's') || i > 3)
1389
{
1390
error(location, 3018, "invalid subscript '" + subscript + '\'');
1391
return false;
1392
}
1393
}
1394
1395
// Promote scalar to vector type using cast
1396
auto target_type = exp.type;
1397
target_type.rows = static_cast<unsigned int>(length);
1398
1399
exp.add_cast_operation(target_type);
1400
1401
if (length > 1)
1402
exp.type.qualifiers |= type::q_const;
1403
}
1404
else
1405
{
1406
error(location, 3018, "invalid subscript '" + subscript + '\'');
1407
return false;
1408
}
1409
}
1410
else if (accept('['))
1411
{
1412
if (!exp.type.is_array() && !exp.type.is_vector() && !exp.type.is_matrix())
1413
{
1414
error(_token.location, 3121, "array, matrix, vector, or indexable object type expected in index expression");
1415
return false;
1416
}
1417
1418
// Parse index expression
1419
expression index_exp;
1420
if (!parse_expression(index_exp) || !expect(']'))
1421
return false;
1422
1423
if (!index_exp.type.is_scalar() || !index_exp.type.is_integral())
1424
{
1425
error(index_exp.location, 3120, "invalid type for index - index must be an integer scalar");
1426
return false;
1427
}
1428
1429
// Add index expression to current access chain
1430
if (index_exp.is_constant)
1431
{
1432
// Check array bounds if known
1433
if (exp.type.is_bounded_array() && index_exp.constant.as_uint[0] >= exp.type.array_length)
1434
{
1435
error(index_exp.location, 3504, "array index out of bounds");
1436
return false;
1437
}
1438
1439
exp.add_constant_index_access(index_exp.constant.as_uint[0]);
1440
}
1441
else
1442
{
1443
if (exp.is_constant)
1444
{
1445
// To handle a dynamic index into a constant means we need to create a local variable first or else any of the indexing instructions do not work
1446
const codegen::id temp_variable = _codegen->define_variable(location, exp.type, std::string(), false, _codegen->emit_constant(exp.type, exp.constant));
1447
exp.reset_to_lvalue(exp.location, temp_variable, exp.type);
1448
}
1449
1450
exp.add_dynamic_index_access(_codegen->emit_load(index_exp));
1451
}
1452
}
1453
else
1454
{
1455
break;
1456
}
1457
}
1458
1459
return true;
1460
}
1461
1462
bool reshadefx::parser::parse_expression_multary(expression &lhs_exp, unsigned int left_precedence)
1463
{
1464
// Parse left hand side of the expression
1465
if (!parse_expression_unary(lhs_exp))
1466
return false;
1467
1468
// Check if an operator exists so that this is a binary or ternary expression
1469
unsigned int right_precedence;
1470
1471
while (peek_multary_op(right_precedence))
1472
{
1473
// Only process this operator if it has a lower precedence than the current operation, otherwise leave it for later and abort
1474
if (right_precedence <= left_precedence)
1475
break;
1476
1477
// Finally consume the operator token
1478
consume();
1479
1480
const tokenid op = _token.id;
1481
1482
// Check if this is a binary or ternary operation
1483
if (op != tokenid::question)
1484
{
1485
#if RESHADEFX_SHORT_CIRCUIT
1486
codegen::id lhs_block = 0;
1487
codegen::id rhs_block = 0;
1488
codegen::id merge_block = 0;
1489
1490
// Switch block to a new one before parsing right-hand side value in case it needs to be skipped during short-circuiting
1491
if (op == tokenid::ampersand_ampersand || op == tokenid::pipe_pipe)
1492
{
1493
lhs_block = _codegen->set_block(0);
1494
rhs_block = _codegen->create_block();
1495
merge_block = _codegen->create_block();
1496
1497
_codegen->enter_block(rhs_block);
1498
}
1499
#endif
1500
// Parse the right hand side of the binary operation
1501
expression rhs_exp;
1502
if (!parse_expression_multary(rhs_exp, right_precedence))
1503
return false;
1504
1505
// Deduce the result base type based on implicit conversion rules
1506
type type = type::merge(lhs_exp.type, rhs_exp.type);
1507
bool is_bool_result = false;
1508
1509
// Do some error checking depending on the operator
1510
if (op == tokenid::equal_equal || op == tokenid::exclaim_equal)
1511
{
1512
// Equality checks return a boolean value
1513
is_bool_result = true;
1514
1515
// Cannot check equality between incompatible types
1516
if (lhs_exp.type.is_array() || rhs_exp.type.is_array() || lhs_exp.type.struct_definition != rhs_exp.type.struct_definition)
1517
{
1518
error(rhs_exp.location, 3020, "type mismatch");
1519
return false;
1520
}
1521
}
1522
else if (op == tokenid::ampersand || op == tokenid::pipe || op == tokenid::caret)
1523
{
1524
if (type.is_boolean())
1525
type.base = type::t_int;
1526
1527
// Cannot perform bitwise operations on non-integral types
1528
if (!lhs_exp.type.is_integral())
1529
{
1530
error(lhs_exp.location, 3082, "int or unsigned int type required");
1531
return false;
1532
}
1533
if (!rhs_exp.type.is_integral())
1534
{
1535
error(rhs_exp.location, 3082, "int or unsigned int type required");
1536
return false;
1537
}
1538
}
1539
else
1540
{
1541
if (op == tokenid::ampersand_ampersand || op == tokenid::pipe_pipe)
1542
type.base = type::t_bool;
1543
else if (op == tokenid::less || op == tokenid::less_equal || op == tokenid::greater || op == tokenid::greater_equal)
1544
is_bool_result = true; // Logical operations return a boolean value
1545
else if (type.is_boolean())
1546
type.base = type::t_int; // Arithmetic with boolean values treats the operands as integers
1547
1548
// Cannot perform arithmetic operations on non-basic types
1549
if (!lhs_exp.type.is_scalar() && !lhs_exp.type.is_vector() && !lhs_exp.type.is_matrix())
1550
{
1551
error(lhs_exp.location, 3022, "scalar, vector, or matrix expected");
1552
return false;
1553
}
1554
if (!rhs_exp.type.is_scalar() && !rhs_exp.type.is_vector() && !rhs_exp.type.is_matrix())
1555
{
1556
error(rhs_exp.location, 3022, "scalar, vector, or matrix expected");
1557
return false;
1558
}
1559
}
1560
1561
// Perform implicit type conversion
1562
if (lhs_exp.type.components() > type.components())
1563
warning(lhs_exp.location, 3206, "implicit truncation of vector type");
1564
if (rhs_exp.type.components() > type.components())
1565
warning(rhs_exp.location, 3206, "implicit truncation of vector type");
1566
1567
lhs_exp.add_cast_operation(type);
1568
rhs_exp.add_cast_operation(type);
1569
1570
#if RESHADEFX_SHORT_CIRCUIT
1571
// Reset block to left-hand side since the load of the left-hand side value has to happen in there
1572
if (op == tokenid::ampersand_ampersand || op == tokenid::pipe_pipe)
1573
_codegen->set_block(lhs_block);
1574
#endif
1575
1576
// Constant expressions can be evaluated at compile time
1577
if (rhs_exp.is_constant && lhs_exp.evaluate_constant_expression(op, rhs_exp.constant))
1578
continue;
1579
1580
const codegen::id lhs_value = _codegen->emit_load(lhs_exp);
1581
1582
#if RESHADEFX_SHORT_CIRCUIT
1583
// Short circuit for logical && and || operators
1584
if (op == tokenid::ampersand_ampersand || op == tokenid::pipe_pipe)
1585
{
1586
// Emit "if ( lhs) result = rhs" for && expression
1587
codegen::id condition_value = lhs_value;
1588
// Emit "if (!lhs) result = rhs" for || expression
1589
if (op == tokenid::pipe_pipe)
1590
condition_value = _codegen->emit_unary_op(lhs_exp.location, tokenid::exclaim, type, lhs_value);
1591
1592
_codegen->leave_block_and_branch_conditional(condition_value, rhs_block, merge_block);
1593
1594
_codegen->set_block(rhs_block);
1595
// Only load value of right hand side expression after entering the second block
1596
const codegen::id rhs_value = _codegen->emit_load(rhs_exp);
1597
_codegen->leave_block_and_branch(merge_block);
1598
1599
_codegen->enter_block(merge_block);
1600
1601
const codegen::id result_value = _codegen->emit_phi(lhs_exp.location, condition_value, lhs_block, rhs_value, rhs_block, lhs_value, lhs_block, type);
1602
1603
lhs_exp.reset_to_rvalue(lhs_exp.location, result_value, type);
1604
continue;
1605
}
1606
#endif
1607
const codegen::id rhs_value = _codegen->emit_load(rhs_exp);
1608
1609
// Certain operations return a boolean type instead of the type of the input expressions
1610
if (is_bool_result)
1611
type = { type::t_bool, type.rows, type.cols };
1612
1613
const codegen::id result_value = _codegen->emit_binary_op(lhs_exp.location, op, type, lhs_exp.type, lhs_value, rhs_value);
1614
1615
lhs_exp.reset_to_rvalue(lhs_exp.location, result_value, type);
1616
}
1617
else
1618
{
1619
// A conditional expression needs a scalar or vector type condition
1620
if (!lhs_exp.type.is_scalar() && !lhs_exp.type.is_vector())
1621
{
1622
error(lhs_exp.location, 3022, "boolean or vector expression expected");
1623
return false;
1624
}
1625
1626
#if RESHADEFX_SHORT_CIRCUIT
1627
// Switch block to a new one before parsing first part in case it needs to be skipped during short-circuiting
1628
const codegen::id merge_block = _codegen->create_block();
1629
const codegen::id condition_block = _codegen->set_block(0);
1630
codegen::id true_block = _codegen->create_block();
1631
codegen::id false_block = _codegen->create_block();
1632
1633
_codegen->enter_block(true_block);
1634
#endif
1635
// Parse the first part of the right hand side of the ternary operation
1636
expression true_exp;
1637
if (!parse_expression(true_exp))
1638
return false;
1639
1640
if (!expect(':'))
1641
return false;
1642
1643
#if RESHADEFX_SHORT_CIRCUIT
1644
// Switch block to a new one before parsing second part in case it needs to be skipped during short-circuiting
1645
_codegen->set_block(0);
1646
_codegen->enter_block(false_block);
1647
#endif
1648
// Parse the second part of the right hand side of the ternary operation
1649
expression false_exp;
1650
if (!parse_expression_assignment(false_exp))
1651
return false;
1652
1653
// Check that the condition dimension matches that of at least one side
1654
if (lhs_exp.type.rows != true_exp.type.rows && lhs_exp.type.cols != true_exp.type.cols)
1655
{
1656
error(lhs_exp.location, 3020, "dimension of conditional does not match value");
1657
return false;
1658
}
1659
1660
// Check that the two value expressions can be converted between each other
1661
if (true_exp.type.array_length != false_exp.type.array_length || true_exp.type.struct_definition != false_exp.type.struct_definition)
1662
{
1663
error(false_exp.location, 3020, "type mismatch between conditional values");
1664
return false;
1665
}
1666
1667
// Deduce the result base type based on implicit conversion rules
1668
const type type = type::merge(true_exp.type, false_exp.type);
1669
1670
if (true_exp.type.components() > type.components())
1671
warning(true_exp.location, 3206, "implicit truncation of vector type");
1672
if (false_exp.type.components() > type.components())
1673
warning(false_exp.location, 3206, "implicit truncation of vector type");
1674
1675
#if RESHADEFX_SHORT_CIRCUIT
1676
// Reset block to left-hand side since the load of the condition value has to happen in there
1677
_codegen->set_block(condition_block);
1678
#else
1679
// The conditional operator instruction expects the condition to be a boolean type
1680
lhs_exp.add_cast_operation({ type::t_bool, type.rows, 1 });
1681
#endif
1682
true_exp.add_cast_operation(type);
1683
false_exp.add_cast_operation(type);
1684
1685
// Load condition value from expression
1686
const codegen::id condition_value = _codegen->emit_load(lhs_exp);
1687
1688
#if RESHADEFX_SHORT_CIRCUIT
1689
_codegen->leave_block_and_branch_conditional(condition_value, true_block, false_block);
1690
1691
_codegen->set_block(true_block);
1692
// Only load true expression value after entering the first block
1693
const codegen::id true_value = _codegen->emit_load(true_exp);
1694
true_block = _codegen->leave_block_and_branch(merge_block);
1695
1696
_codegen->set_block(false_block);
1697
// Only load false expression value after entering the second block
1698
const codegen::id false_value = _codegen->emit_load(false_exp);
1699
false_block = _codegen->leave_block_and_branch(merge_block);
1700
1701
_codegen->enter_block(merge_block);
1702
1703
const codegen::id result_value = _codegen->emit_phi(lhs_exp.location, condition_value, condition_block, true_value, true_block, false_value, false_block, type);
1704
#else
1705
const codegen::id true_value = _codegen->emit_load(true_exp);
1706
const codegen::id false_value = _codegen->emit_load(false_exp);
1707
1708
const codegen::id result_value = _codegen->emit_ternary_op(lhs_exp.location, op, type, condition_value, true_value, false_value);
1709
#endif
1710
lhs_exp.reset_to_rvalue(lhs_exp.location, result_value, type);
1711
}
1712
}
1713
1714
return true;
1715
}
1716
1717
bool reshadefx::parser::parse_expression_assignment(expression &lhs_exp)
1718
{
1719
// Parse left hand side of the expression
1720
if (!parse_expression_multary(lhs_exp))
1721
return false;
1722
1723
// Check if an operator exists so that this is an assignment
1724
if (accept_assignment_op())
1725
{
1726
// Remember the operator token before parsing the expression that follows it
1727
const tokenid op = _token.id;
1728
1729
// Parse right hand side of the assignment expression
1730
// This may be another assignment expression to support chains like "a = b = c = 0;"
1731
expression rhs_exp;
1732
if (!parse_expression_assignment(rhs_exp))
1733
return false;
1734
1735
// Check if the assignment is valid
1736
if (lhs_exp.type.has(type::q_const) || !lhs_exp.is_lvalue)
1737
{
1738
error(lhs_exp.location, 3025, "l-value specifies const object");
1739
return false;
1740
}
1741
if (!type::rank(lhs_exp.type, rhs_exp.type))
1742
{
1743
error(rhs_exp.location, 3020, "cannot convert these types (from " + rhs_exp.type.description() + " to " + lhs_exp.type.description() + ')');
1744
return false;
1745
}
1746
1747
// Cannot perform bitwise operations on non-integral types
1748
if (!lhs_exp.type.is_integral() && (op == tokenid::ampersand_equal || op == tokenid::pipe_equal || op == tokenid::caret_equal))
1749
{
1750
error(lhs_exp.location, 3082, "int or unsigned int type required");
1751
return false;
1752
}
1753
1754
// Perform implicit type conversion of right hand side value
1755
if (rhs_exp.type.components() > lhs_exp.type.components())
1756
warning(rhs_exp.location, 3206, "implicit truncation of vector type");
1757
1758
rhs_exp.add_cast_operation(lhs_exp.type);
1759
1760
codegen::id result_value = _codegen->emit_load(rhs_exp);
1761
1762
// Check if this is an assignment with an additional arithmetic instruction
1763
if (op != tokenid::equal)
1764
{
1765
// Load value for modification
1766
const codegen::id lhs_value = _codegen->emit_load(lhs_exp);
1767
1768
// Handle arithmetic assignment operation
1769
result_value = _codegen->emit_binary_op(lhs_exp.location, op, lhs_exp.type, lhs_value, result_value);
1770
}
1771
1772
// Write result back to variable
1773
_codegen->emit_store(lhs_exp, result_value);
1774
1775
// Return the result value since you can write assignments within expressions
1776
lhs_exp.reset_to_rvalue(lhs_exp.location, result_value, lhs_exp.type);
1777
}
1778
1779
return true;
1780
}
1781
1782