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