dep/reshadefx: Update to 7bdfb03
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,16 +3,16 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "effect_lexer.hpp"
|
||||
#include "effect_codegen.hpp"
|
||||
#include <cmath> // fmod
|
||||
#include "effect_expression.hpp"
|
||||
#include <cmath> // std::fmod
|
||||
#include <cassert>
|
||||
#include <cstring> // memcpy, memset
|
||||
#include <algorithm> // std::min, std::max
|
||||
#include <cstring> // std::memcpy, std::memset
|
||||
#include <algorithm> // std::max, std::min
|
||||
|
||||
reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
|
||||
{
|
||||
type result = { std::max(lhs.base, rhs.base) };
|
||||
type result;
|
||||
result.base = std::max(lhs.base, rhs.base);
|
||||
|
||||
// Non-numeric types cannot be vectors or matrices
|
||||
if (!result.is_numeric())
|
||||
@ -35,11 +35,14 @@ reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
|
||||
// Some qualifiers propagate to the result
|
||||
result.qualifiers = (lhs.qualifiers & type::q_precise) | (rhs.qualifiers & type::q_precise);
|
||||
|
||||
// In case this is a structure, assume they are the same
|
||||
result.definition = rhs.definition;
|
||||
assert(lhs.definition == rhs.definition || lhs.definition == 0);
|
||||
// Cannot merge array types, assume no arrays
|
||||
result.array_length = 0;
|
||||
assert(lhs.array_length == 0 && rhs.array_length == 0);
|
||||
|
||||
// In case this is a structure, assume they are the same
|
||||
result.struct_definition = rhs.struct_definition;
|
||||
assert(lhs.struct_definition == rhs.struct_definition || lhs.struct_definition == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -48,101 +51,101 @@ std::string reshadefx::type::description() const
|
||||
std::string result;
|
||||
switch (base)
|
||||
{
|
||||
case reshadefx::type::t_void:
|
||||
case t_void:
|
||||
result = "void";
|
||||
break;
|
||||
case reshadefx::type::t_bool:
|
||||
case t_bool:
|
||||
result = "bool";
|
||||
break;
|
||||
case reshadefx::type::t_min16int:
|
||||
case t_min16int:
|
||||
result = "min16int";
|
||||
break;
|
||||
case reshadefx::type::t_int:
|
||||
case t_int:
|
||||
result = "int";
|
||||
break;
|
||||
case reshadefx::type::t_min16uint:
|
||||
case t_min16uint:
|
||||
result = "min16uint";
|
||||
break;
|
||||
case reshadefx::type::t_uint:
|
||||
case t_uint:
|
||||
result = "uint";
|
||||
break;
|
||||
case reshadefx::type::t_min16float:
|
||||
case t_min16float:
|
||||
result = "min16float";
|
||||
break;
|
||||
case reshadefx::type::t_float:
|
||||
case t_float:
|
||||
result = "float";
|
||||
break;
|
||||
case reshadefx::type::t_string:
|
||||
case t_string:
|
||||
result = "string";
|
||||
break;
|
||||
case reshadefx::type::t_struct:
|
||||
case t_struct:
|
||||
result = "struct";
|
||||
break;
|
||||
case reshadefx::type::t_texture1d:
|
||||
case t_texture1d:
|
||||
result = "texture1D";
|
||||
break;
|
||||
case reshadefx::type::t_texture2d:
|
||||
case t_texture2d:
|
||||
result = "texture2D";
|
||||
break;
|
||||
case reshadefx::type::t_texture3d:
|
||||
case t_texture3d:
|
||||
result = "texture3D";
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_int:
|
||||
case t_sampler1d_int:
|
||||
result = "sampler1D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_int:
|
||||
case t_sampler2d_int:
|
||||
result = "sampler2D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_int:
|
||||
case t_sampler3d_int:
|
||||
result = "sampler3D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_uint:
|
||||
case t_sampler1d_uint:
|
||||
result = "sampler1D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_uint:
|
||||
case t_sampler2d_uint:
|
||||
result = "sampler2D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_uint:
|
||||
case t_sampler3d_uint:
|
||||
result = "sampler3D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler1d_float:
|
||||
case t_sampler1d_float:
|
||||
result = "sampler1D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler2d_float:
|
||||
case t_sampler2d_float:
|
||||
result = "sampler2D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_sampler3d_float:
|
||||
case t_sampler3d_float:
|
||||
result = "sampler3D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_int:
|
||||
case t_storage1d_int:
|
||||
result = "storage1D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_int:
|
||||
case t_storage2d_int:
|
||||
result = "storage2D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_int:
|
||||
case t_storage3d_int:
|
||||
result = "storage3D<int" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_uint:
|
||||
case t_storage1d_uint:
|
||||
result = "storage1D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_uint:
|
||||
case t_storage2d_uint:
|
||||
result = "storage2D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_uint:
|
||||
case t_storage3d_uint:
|
||||
result = "storage3D<uint" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage1d_float:
|
||||
case t_storage1d_float:
|
||||
result = "storage1D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage2d_float:
|
||||
case t_storage2d_float:
|
||||
result = "storage2D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_storage3d_float:
|
||||
case t_storage3d_float:
|
||||
result = "storage3D<float" + std::to_string(rows) + '>';
|
||||
break;
|
||||
case reshadefx::type::t_function:
|
||||
result = "function";
|
||||
case t_function:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -157,7 +160,7 @@ std::string reshadefx::type::description() const
|
||||
if (is_array())
|
||||
{
|
||||
result += '[';
|
||||
if (array_length > 0)
|
||||
if (is_bounded_array())
|
||||
result += std::to_string(array_length);
|
||||
result += ']';
|
||||
}
|
||||
@ -179,7 +182,7 @@ void reshadefx::expression::reset_to_lvalue(const reshadefx::location &loc, uint
|
||||
type.qualifiers |= type::q_const;
|
||||
|
||||
// Strip away global variable qualifiers
|
||||
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
|
||||
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
|
||||
}
|
||||
void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint32_t in_base, const reshadefx::type &in_type)
|
||||
{
|
||||
@ -192,7 +195,7 @@ void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint
|
||||
chain.clear();
|
||||
|
||||
// Strip away global variable qualifiers
|
||||
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared);
|
||||
type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
|
||||
}
|
||||
|
||||
void reshadefx::expression::reset_to_rvalue_constant(const reshadefx::location &loc, bool data)
|
||||
@ -290,7 +293,7 @@ void reshadefx::expression::add_cast_operation(const reshadefx::type &cast_type)
|
||||
constant.as_float[i] = static_cast<float>(constant.as_int[i]);
|
||||
};
|
||||
|
||||
for (auto &element : constant.array_data)
|
||||
for (struct constant &element : constant.array_data)
|
||||
cast_constant(element, type, cast_type);
|
||||
|
||||
cast_constant(constant, type, cast_type);
|
||||
@ -320,7 +323,7 @@ void reshadefx::expression::add_dynamic_index_access(uint32_t index_expression)
|
||||
assert(!is_constant); // Cannot have dynamic indexing into constant in SPIR-V
|
||||
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
|
||||
|
||||
auto prev_type = type;
|
||||
struct type prev_type = type;
|
||||
|
||||
if (type.is_array())
|
||||
{
|
||||
@ -342,11 +345,11 @@ void reshadefx::expression::add_constant_index_access(unsigned int index)
|
||||
{
|
||||
assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
|
||||
|
||||
auto prev_type = type;
|
||||
struct type prev_type = type;
|
||||
|
||||
if (type.is_array())
|
||||
{
|
||||
assert(type.array_length < 0 || index < static_cast<unsigned int>(type.array_length));
|
||||
assert(index < type.array_length);
|
||||
|
||||
type.array_length = 0;
|
||||
}
|
||||
@ -389,7 +392,7 @@ void reshadefx::expression::add_swizzle_access(const signed char swizzle[4], uns
|
||||
{
|
||||
assert(type.is_numeric() && !type.is_array());
|
||||
|
||||
const auto prev_type = type;
|
||||
const struct type prev_type = type;
|
||||
|
||||
type.rows = length;
|
||||
type.cols = 1;
|
||||
|
||||
@ -18,7 +18,7 @@ enum token_type
|
||||
};
|
||||
|
||||
// Lookup table which translates a given char to a token type
|
||||
static const unsigned type_lookup[256] = {
|
||||
static const unsigned int s_type_lookup[256] = {
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SPACE,
|
||||
'\n', SPACE, SPACE, SPACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
@ -35,7 +35,7 @@ static const unsigned type_lookup[256] = {
|
||||
};
|
||||
|
||||
// Lookup tables which translate a given string literal to a token and backwards
|
||||
static const std::unordered_map<tokenid, std::string_view> token_lookup = {
|
||||
static const std::unordered_map<tokenid, std::string_view> s_token_lookup = {
|
||||
{ tokenid::end_of_file, "end of file" },
|
||||
{ tokenid::exclaim, "!" },
|
||||
{ tokenid::hash, "#" },
|
||||
@ -205,7 +205,7 @@ static const std::unordered_map<tokenid, std::string_view> token_lookup = {
|
||||
{ tokenid::storage2d, "storage2D" },
|
||||
{ tokenid::storage3d, "storage3D" },
|
||||
};
|
||||
static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
|
||||
static const std::unordered_map<std::string_view, tokenid> s_keyword_lookup = {
|
||||
{ "asm", tokenid::reserved },
|
||||
{ "asm_fragment", tokenid::reserved },
|
||||
{ "auto", tokenid::reserved },
|
||||
@ -439,7 +439,7 @@ static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
|
||||
{ "volatile", tokenid::volatile_ },
|
||||
{ "while", tokenid::while_ }
|
||||
};
|
||||
static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup = {
|
||||
static const std::unordered_map<std::string_view, tokenid> s_pp_directive_lookup = {
|
||||
{ "define", tokenid::hash_def },
|
||||
{ "undef", tokenid::hash_undef },
|
||||
{ "if", tokenid::hash_if },
|
||||
@ -454,15 +454,15 @@ static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup =
|
||||
{ "include", tokenid::hash_include },
|
||||
};
|
||||
|
||||
static inline bool is_octal_digit(char c)
|
||||
static bool is_octal_digit(char c)
|
||||
{
|
||||
return static_cast<unsigned>(c - '0') < 8;
|
||||
}
|
||||
static inline bool is_decimal_digit(char c)
|
||||
static bool is_decimal_digit(char c)
|
||||
{
|
||||
return static_cast<unsigned>(c - '0') < 10;
|
||||
}
|
||||
static inline bool is_hexadecimal_digit(char c)
|
||||
static bool is_hexadecimal_digit(char c)
|
||||
{
|
||||
return is_decimal_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
@ -504,8 +504,8 @@ static long long octal_to_decimal(long long n)
|
||||
|
||||
std::string reshadefx::token::id_to_name(tokenid id)
|
||||
{
|
||||
const auto it = token_lookup.find(id);
|
||||
if (it != token_lookup.end())
|
||||
const auto it = s_token_lookup.find(id);
|
||||
if (it != s_token_lookup.end())
|
||||
return std::string(it->second);
|
||||
return "unknown";
|
||||
}
|
||||
@ -526,7 +526,7 @@ next_token:
|
||||
assert(_cur <= _end);
|
||||
|
||||
// Do a character type lookup for the current character
|
||||
switch (type_lookup[uint8_t(*_cur)])
|
||||
switch (s_type_lookup[uint8_t(*_cur)])
|
||||
{
|
||||
case 0xFF: // EOF
|
||||
tok.id = tokenid::end_of_file;
|
||||
@ -635,7 +635,7 @@ next_token:
|
||||
tok.id = tokenid::minus;
|
||||
break;
|
||||
case '.':
|
||||
if (type_lookup[uint8_t(_cur[1])] == DIGIT)
|
||||
if (s_type_lookup[uint8_t(_cur[1])] == DIGIT)
|
||||
parse_numeric_literal(tok);
|
||||
else if (_cur[1] == '.' && _cur[2] == '.')
|
||||
tok.id = tokenid::ellipsis,
|
||||
@ -805,7 +805,7 @@ void reshadefx::lexer::skip_space()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type_lookup[uint8_t(*_cur)] == SPACE)
|
||||
if (s_type_lookup[uint8_t(*_cur)] == SPACE)
|
||||
skip(1);
|
||||
else
|
||||
break;
|
||||
@ -841,7 +841,7 @@ void reshadefx::lexer::parse_identifier(token &tok) const
|
||||
auto *const begin = _cur, *end = begin;
|
||||
|
||||
// Skip to the end of the identifier sequence
|
||||
while (type_lookup[uint8_t(*end)] == IDENT || type_lookup[uint8_t(*end)] == DIGIT)
|
||||
while (s_type_lookup[uint8_t(*end)] == IDENT || s_type_lookup[uint8_t(*end)] == DIGIT)
|
||||
end++;
|
||||
|
||||
tok.id = tokenid::identifier;
|
||||
@ -852,8 +852,8 @@ void reshadefx::lexer::parse_identifier(token &tok) const
|
||||
if (_ignore_keywords)
|
||||
return;
|
||||
|
||||
if (const auto it = keyword_lookup.find(tok.literal_as_string);
|
||||
it != keyword_lookup.end())
|
||||
if (const auto it = s_keyword_lookup.find(tok.literal_as_string);
|
||||
it != s_keyword_lookup.end())
|
||||
tok.id = it->second;
|
||||
}
|
||||
bool reshadefx::lexer::parse_pp_directive(token &tok)
|
||||
@ -862,8 +862,8 @@ bool reshadefx::lexer::parse_pp_directive(token &tok)
|
||||
skip_space(); // Skip any space between the '#' and directive
|
||||
parse_identifier(tok);
|
||||
|
||||
if (const auto it = pp_directive_lookup.find(tok.literal_as_string);
|
||||
it != pp_directive_lookup.end())
|
||||
if (const auto it = s_pp_directive_lookup.find(tok.literal_as_string);
|
||||
it != s_pp_directive_lookup.end())
|
||||
{
|
||||
tok.id = it->second;
|
||||
return true;
|
||||
@ -999,6 +999,9 @@ void reshadefx::lexer::parse_string_literal(token &tok, bool escape)
|
||||
|
||||
tok.id = tokenid::string_literal;
|
||||
tok.length = end - begin + 1;
|
||||
|
||||
// Free up unused memory
|
||||
tok.literal_as_string.shrink_to_fit();
|
||||
}
|
||||
void reshadefx::lexer::parse_numeric_literal(token &tok) const
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,8 +5,8 @@
|
||||
|
||||
#include "effect_lexer.hpp"
|
||||
#include "effect_preprocessor.hpp"
|
||||
#include <cstdio> // fclose, fopen, fread, fseek
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <algorithm> // std::find_if
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -52,7 +52,7 @@ enum macro_replacement
|
||||
macro_replacement_stringize = '\xFE',
|
||||
};
|
||||
|
||||
static const int precedence_lookup[] = {
|
||||
static const int s_precedence_lookup[] = {
|
||||
0, 1, 2, 3, 4, // bitwise operators
|
||||
5, 6, 7, 7, 7, 7, // logical operators
|
||||
8, 8, // left shift, right shift
|
||||
@ -61,9 +61,8 @@ static const int precedence_lookup[] = {
|
||||
11, 11, 11, 11 // unary operators
|
||||
};
|
||||
|
||||
static bool read_file(const std::string &path, std::string &data, reshadefx::preprocessor::include_read_file_callback &cb)
|
||||
static bool read_file(const std::string &path, std::string &file_data, reshadefx::preprocessor::include_read_file_callback &cb)
|
||||
{
|
||||
std::string file_data;
|
||||
if (!cb(path, file_data))
|
||||
return false;
|
||||
|
||||
@ -77,29 +76,33 @@ static bool read_file(const std::string &path, std::string &data, reshadefx::pre
|
||||
static_cast<unsigned char>(file_data[2]) == 0xbf)
|
||||
file_data.erase(0, 3);
|
||||
|
||||
data = std::move(file_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data)
|
||||
{
|
||||
std::ifstream file(std::filesystem::path(path), std::ios::binary);
|
||||
if (!file)
|
||||
return false;
|
||||
// Read file contents into memory
|
||||
const std::filesystem::path fspath(path);
|
||||
#ifndef _WIN32
|
||||
FILE *const file = fopen(fspath.c_str(), "rb");
|
||||
#else
|
||||
FILE *const file = _wfsopen(fspath.generic_wstring().c_str(), L"rb", SH_DENYWR);
|
||||
#endif
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
// Read file contents into memory
|
||||
std::error_code ec;
|
||||
const uintmax_t file_size = std::filesystem::file_size(path, ec);
|
||||
if (ec)
|
||||
return false;
|
||||
fseek(file, 0, SEEK_END);
|
||||
const size_t file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
data.reserve(file_size + 1);
|
||||
data.resize(static_cast<size_t>(file_size), '\0');
|
||||
if (!file.read(data.data(), file_size))
|
||||
return false;
|
||||
const size_t file_size_read = fread(data.data(), 1, file_size, file);
|
||||
|
||||
// No longer need to have a handle open to the file, since all data was read, so can safely close it
|
||||
fclose(file);
|
||||
|
||||
if (file_size_read != file_size)
|
||||
return false;
|
||||
|
||||
// No longer need to have a handle open to the file, since all data was read, so can safely close it
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,7 +159,8 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
|
||||
// Enforce all input strings to end with a line feed
|
||||
assert(!source_code.empty() && source_code.back() == '\n');
|
||||
|
||||
_success = true; // Clear success flag before parsing a new string
|
||||
// Only consider new errors added below for the success of this call
|
||||
const size_t errors_offset = _errors.length();
|
||||
|
||||
// Give this push a name, so that lexer location starts at a new line
|
||||
// This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line
|
||||
@ -164,15 +168,15 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
|
||||
push(std::move(source_code), path.empty() ? "unknown" : path);
|
||||
parse();
|
||||
|
||||
return _success;
|
||||
return _errors.find(": preprocessor error: ", errors_offset) == std::string::npos;
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> reshadefx::preprocessor::included_files() const
|
||||
{
|
||||
std::vector<std::filesystem::path> files;
|
||||
files.reserve(_file_cache.size());
|
||||
for (const auto &it : _file_cache)
|
||||
files.push_back(std::filesystem::u8path(it.first));
|
||||
for (const std::pair<std::string, std::string> &cache_entry : _file_cache)
|
||||
files.push_back(std::filesystem::u8path(cache_entry.first));
|
||||
return files;
|
||||
}
|
||||
std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_macro_definitions() const
|
||||
@ -189,12 +193,19 @@ std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_m
|
||||
|
||||
void reshadefx::preprocessor::error(const location &location, const std::string &message)
|
||||
{
|
||||
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor error: " + message + '\n';
|
||||
_success = false; // Unset success flag
|
||||
_errors += location.source;
|
||||
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
|
||||
_errors += ": preprocessor error: ";
|
||||
_errors += message;
|
||||
_errors += '\n';
|
||||
}
|
||||
void reshadefx::preprocessor::warning(const location &location, const std::string &message)
|
||||
{
|
||||
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor warning: " + message + '\n';
|
||||
_errors += location.source;
|
||||
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
|
||||
_errors += ": preprocessor warning: ";
|
||||
_errors += message;
|
||||
_errors += '\n';
|
||||
}
|
||||
|
||||
void reshadefx::preprocessor::push(std::string input, const std::string &name)
|
||||
@ -357,32 +368,32 @@ void reshadefx::preprocessor::parse()
|
||||
{
|
||||
case tokenid::hash_if:
|
||||
parse_if();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_ifdef:
|
||||
parse_ifdef();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_ifndef:
|
||||
parse_ifndef();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_else:
|
||||
parse_else();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_elif:
|
||||
parse_elif();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
case tokenid::hash_endif:
|
||||
parse_endif();
|
||||
if (!expect(tokenid::end_of_line))
|
||||
if (!skip && !expect(tokenid::end_of_line))
|
||||
consume_until(tokenid::end_of_line);
|
||||
continue;
|
||||
default:
|
||||
@ -511,11 +522,18 @@ void reshadefx::preprocessor::parse_if()
|
||||
level.pp_token = _token;
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
|
||||
level.value = evaluate_expression();
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
|
||||
level.value = evaluate_expression();
|
||||
level.skipping = !level.value;
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
@ -528,16 +546,23 @@ void reshadefx::preprocessor::parse_ifdef()
|
||||
if (!expect(tokenid::identifier))
|
||||
return;
|
||||
|
||||
level.value = is_defined(_token.literal_as_string);
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.value = is_defined(_token.literal_as_string);
|
||||
level.skipping = !level.value;
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
// Only add to used macro list if this #ifdef is active and the macro was not defined before
|
||||
if (!parent_skipping)
|
||||
// Only add to used macro list if this #ifdef is active and the macro was not defined before
|
||||
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
|
||||
_used_macros.emplace(_token.literal_as_string);
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
void reshadefx::preprocessor::parse_ifndef()
|
||||
{
|
||||
@ -548,16 +573,23 @@ void reshadefx::preprocessor::parse_ifndef()
|
||||
if (!expect(tokenid::identifier))
|
||||
return;
|
||||
|
||||
level.value = !is_defined(_token.literal_as_string);
|
||||
|
||||
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
|
||||
level.skipping = parent_skipping || !level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.value = !is_defined(_token.literal_as_string);
|
||||
level.skipping = !level.value;
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
// Only add to used macro list if this #ifndef is active and the macro was not defined before
|
||||
if (!parent_skipping)
|
||||
// Only add to used macro list if this #ifndef is active and the macro was not defined before
|
||||
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
|
||||
_used_macros.emplace(_token.literal_as_string);
|
||||
}
|
||||
|
||||
_if_stack.push_back(std::move(level));
|
||||
}
|
||||
void reshadefx::preprocessor::parse_elif()
|
||||
{
|
||||
@ -573,10 +605,19 @@ void reshadefx::preprocessor::parse_elif()
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
|
||||
const bool condition_result = evaluate_expression();
|
||||
level.skipping = parent_skipping || level.value || !condition_result;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool condition_result = evaluate_expression();
|
||||
level.skipping = level.value || !condition_result;
|
||||
|
||||
if (!level.value) level.value = condition_result;
|
||||
if (!level.value)
|
||||
level.value = condition_result;
|
||||
}
|
||||
}
|
||||
void reshadefx::preprocessor::parse_else()
|
||||
{
|
||||
@ -591,16 +632,25 @@ void reshadefx::preprocessor::parse_else()
|
||||
level.input_index = _current_input_index;
|
||||
|
||||
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
|
||||
level.skipping = parent_skipping || level.value;
|
||||
if (parent_skipping)
|
||||
{
|
||||
level.value = false;
|
||||
level.skipping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.skipping = parent_skipping || level.value;
|
||||
|
||||
if (!level.value) level.value = true;
|
||||
if (!level.value)
|
||||
level.value = true;
|
||||
}
|
||||
}
|
||||
void reshadefx::preprocessor::parse_endif()
|
||||
{
|
||||
if (_if_stack.empty())
|
||||
error(_token.location, "missing #if for #endif");
|
||||
else
|
||||
_if_stack.pop_back();
|
||||
return error(_token.location, "missing #if for #endif");
|
||||
|
||||
_if_stack.pop_back();
|
||||
}
|
||||
|
||||
void reshadefx::preprocessor::parse_error()
|
||||
@ -927,8 +977,8 @@ bool reshadefx::preprocessor::evaluate_expression()
|
||||
break;
|
||||
|
||||
if (left_associative ?
|
||||
(precedence_lookup[op] > precedence_lookup[prev_op]) :
|
||||
(precedence_lookup[op] >= precedence_lookup[prev_op]))
|
||||
(s_precedence_lookup[op] > s_precedence_lookup[prev_op]) :
|
||||
(s_precedence_lookup[op] >= s_precedence_lookup[prev_op]))
|
||||
break;
|
||||
|
||||
stack_index--;
|
||||
@ -1016,9 +1066,13 @@ bool reshadefx::preprocessor::evaluate_expression()
|
||||
BINARY_OPERATION(-);
|
||||
break;
|
||||
case op_modulo:
|
||||
if (stack[stack_index - 1] == 0)
|
||||
return error(_token.location, "right operand of '%' is zero"), 0;
|
||||
BINARY_OPERATION(%);
|
||||
break;
|
||||
case op_divide:
|
||||
if (stack[stack_index - 1] == 0)
|
||||
return error(_token.location, "division by zero"), 0;
|
||||
BINARY_OPERATION(/);
|
||||
break;
|
||||
case op_multiply:
|
||||
@ -1068,12 +1122,24 @@ bool reshadefx::preprocessor::evaluate_identifier_as_macro()
|
||||
push(escape_string(file_stem.u8string()));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_STEM_HASH__")
|
||||
{
|
||||
const std::filesystem::path file_stem = std::filesystem::u8path(_token.location.source).stem();
|
||||
push(std::to_string(std::hash<std::string>()(file_stem.u8string()) & 0xFFFFFFFF));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_NAME__")
|
||||
{
|
||||
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
|
||||
push(escape_string(file_name.u8string()));
|
||||
return true;
|
||||
}
|
||||
if (_token.literal_as_string == "__FILE_NAME_HASH__")
|
||||
{
|
||||
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
|
||||
push(std::to_string(std::hash<std::string>()(file_name.u8string()) & 0xFFFFFFFF));
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto it = _macros.find(_token.literal_as_string);
|
||||
if (it == _macros.end())
|
||||
|
||||
@ -13,25 +13,23 @@
|
||||
#include <algorithm> // std::upper_bound, std::sort
|
||||
#include <functional> // std::greater
|
||||
|
||||
enum class intrinsic_id : uint32_t
|
||||
enum class intrinsic_id
|
||||
{
|
||||
#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i,
|
||||
#include "effect_symbol_table_intrinsics.inl"
|
||||
};
|
||||
|
||||
struct intrinsic
|
||||
struct intrinsic : reshadefx::function
|
||||
{
|
||||
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types) : id(id)
|
||||
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types)
|
||||
{
|
||||
function.name = name;
|
||||
function.return_type = ret_type;
|
||||
function.parameter_list.reserve(arg_types.size());
|
||||
function::return_type = ret_type;
|
||||
function::id = static_cast<uint32_t>(id);
|
||||
function::name = name;
|
||||
function::parameter_list.reserve(arg_types.size());
|
||||
for (const reshadefx::type &arg_type : arg_types)
|
||||
function.parameter_list.push_back({ arg_type });
|
||||
function::parameter_list.push_back({ arg_type });
|
||||
}
|
||||
|
||||
intrinsic_id id;
|
||||
reshadefx::function_info function;
|
||||
};
|
||||
|
||||
#define void { reshadefx::type::t_void }
|
||||
@ -130,48 +128,17 @@ static const intrinsic s_intrinsics[] =
|
||||
#undef uint2
|
||||
#undef uint3
|
||||
#undef uint4
|
||||
#undef float1
|
||||
#undef float
|
||||
#undef float2
|
||||
#undef float3
|
||||
#undef float4
|
||||
#undef float2x2
|
||||
#undef float3x3
|
||||
#undef float4x4
|
||||
#undef out_float
|
||||
#undef out_float2
|
||||
#undef out_float3
|
||||
#undef out_float4
|
||||
#undef sampler1d_int
|
||||
#undef sampler2d_int
|
||||
#undef sampler3d_int
|
||||
#undef sampler1d_uint
|
||||
#undef sampler2d_uint
|
||||
#undef sampler3d_uint
|
||||
#undef sampler1d_float4
|
||||
#undef sampler2d_float4
|
||||
#undef sampler3d_float4
|
||||
#undef storage1d_int
|
||||
#undef storage2d_int
|
||||
#undef storage3d_int
|
||||
#undef storage1d_uint
|
||||
#undef storage2d_uint
|
||||
#undef storage3d_uint
|
||||
#undef storage1d_float4
|
||||
#undef storage2d_float4
|
||||
#undef storage3d_float4
|
||||
#undef inout_storage1d_int
|
||||
#undef inout_storage2d_int
|
||||
#undef inout_storage3d_int
|
||||
#undef inout_storage1d_uint
|
||||
#undef inout_storage2d_uint
|
||||
#undef inout_storage3d_uint
|
||||
|
||||
unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
{
|
||||
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.array_length > 0 && dst.array_length > 0))
|
||||
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.is_bounded_array() && dst.is_bounded_array()))
|
||||
return 0; // Arrays of different sizes are not compatible
|
||||
if (src.is_struct() || dst.is_struct())
|
||||
return src.definition == dst.definition ? 32 : 0; // Structs are only compatible if they are the same type
|
||||
return src.struct_definition == dst.struct_definition ? 32 : 0; // Structs are only compatible if they are the same type
|
||||
if (!src.is_numeric() || !dst.is_numeric())
|
||||
return src.base == dst.base && src.rows == dst.rows && src.cols == dst.cols ? 32 : 0; // Numeric values are not compatible with other types
|
||||
if (src.is_matrix() && (!dst.is_matrix() || src.rows != dst.rows || src.cols != dst.cols))
|
||||
@ -181,7 +148,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
// - Floating point has a higher rank than integer types
|
||||
// - Integer to floating point promotion has a higher rank than floating point to integer conversion
|
||||
// - Signed to unsigned integer conversion has a higher rank than unsigned to signed integer conversion
|
||||
static const int ranks[7][7] = {
|
||||
static const unsigned int ranks[7][7] = {
|
||||
{ 5, 4, 4, 4, 4, 4, 4 }, // bool
|
||||
{ 3, 5, 5, 2, 2, 4, 4 }, // min16int
|
||||
{ 3, 5, 5, 2, 2, 4, 4 }, // int
|
||||
@ -194,7 +161,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
|
||||
assert(src.base > 0 && src.base <= 7); // bool - float
|
||||
assert(dst.base > 0 && dst.base <= 7);
|
||||
|
||||
const int rank = ranks[src.base - 1][dst.base - 1] << 2;
|
||||
const unsigned int rank = ranks[src.base - 1][dst.base - 1] << 2;
|
||||
|
||||
if ((src.is_scalar() && dst.is_vector()))
|
||||
return rank >> 1; // Scalar to vector promotion has a lower rank
|
||||
@ -284,7 +251,7 @@ bool reshadefx::symbol_table::insert_symbol(const std::string &name, const symbo
|
||||
{
|
||||
// Extract scope name
|
||||
scope.name = _current_scope.name.substr(0, pos += 2);
|
||||
const auto previous_scope_name = _current_scope.name.substr(pos);
|
||||
const std::string previous_scope_name = _current_scope.name.substr(pos);
|
||||
|
||||
// Insert symbol into this scope
|
||||
insert_sorted(_symbol_stack[previous_scope_name + name], scoped_symbol { symbol, scope });
|
||||
@ -335,7 +302,7 @@ reshadefx::scoped_symbol reshadefx::symbol_table::find_symbol(const std::string
|
||||
return result;
|
||||
}
|
||||
|
||||
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function_info *function1, const reshadefx::function_info *function2)
|
||||
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function *function1, const reshadefx::function *function2)
|
||||
{
|
||||
const size_t num_arguments = arguments.size();
|
||||
|
||||
@ -388,7 +355,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
{
|
||||
out_data.op = symbol_type::function;
|
||||
|
||||
const function_info *result = nullptr;
|
||||
const function *result = nullptr;
|
||||
unsigned int num_overloads = 0;
|
||||
unsigned int overload_namespace = scope.namespace_level;
|
||||
|
||||
@ -405,7 +372,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
it->scope.namespace_level > scope.namespace_level || (it->scope.namespace_level == scope.namespace_level && it->scope.name != scope.name))
|
||||
continue;
|
||||
|
||||
const function_info *const function = it->function;
|
||||
const function *const function = it->function;
|
||||
|
||||
if (function == nullptr)
|
||||
continue;
|
||||
@ -425,7 +392,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (arguments.size() != function->parameter_list.size())
|
||||
else if (arguments.size() > function->parameter_list.size() || (arguments.size() < function->parameter_list.size() && !function->parameter_list[arguments.size()].has_default_value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -453,18 +420,18 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
|
||||
{
|
||||
for (const intrinsic &intrinsic : s_intrinsics)
|
||||
{
|
||||
if (intrinsic.function.name != name || intrinsic.function.parameter_list.size() != arguments.size())
|
||||
if (intrinsic.name != name || intrinsic.parameter_list.size() != arguments.size())
|
||||
continue;
|
||||
|
||||
// A new possibly-matching intrinsic function was found, compare it against the current result
|
||||
const int comparison = compare_functions(arguments, &intrinsic.function, result);
|
||||
const int comparison = compare_functions(arguments, &intrinsic, result);
|
||||
|
||||
if (comparison < 0) // The new function is a better match
|
||||
{
|
||||
out_data.op = symbol_type::intrinsic;
|
||||
out_data.id = static_cast<uint32_t>(intrinsic.id);
|
||||
out_data.type = intrinsic.function.return_type;
|
||||
out_data.function = &intrinsic.function;
|
||||
out_data.id = intrinsic.id;
|
||||
out_data.type = intrinsic.return_type;
|
||||
out_data.function = &intrinsic;
|
||||
result = out_data.function;
|
||||
num_overloads = 1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user