duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 &param_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 }