GPU: Shader: Use parser for namespace_mutation

Pull Request: https://projects.blender.org/blender/blender/pulls/145496
This commit is contained in:
Clément Foucault
2025-08-31 13:00:44 +02:00
committed by Gitea
parent d47ad68b0c
commit e7bcec779d
2 changed files with 104 additions and 32 deletions

View File

@@ -993,44 +993,58 @@ class Preprocessor {
return str;
}
using namespace std;
using namespace shader::parser;
Parser parser(str, report_error);
std::string out = str;
/* Parse each namespace declaration. */
std::regex regex(R"(namespace (\w+(?:\:\:\w+)*))");
regex_global_search(str, regex, [&](const std::smatch &match) {
std::string namespace_name = match[1].str();
std::string content = get_content_between_balanced_pair(match.suffix().str(), '{', '}');
if (content.find("namespace") != std::string::npos) {
report_error(line_number(match),
char_number(match),
line_str(match),
"Nested namespaces are unsupported.");
return;
}
std::string out_content = content;
/* Parse all global symbols (struct / functions) inside the content. */
std::regex regex(R"([\n\>] ?(?:const )?(\w+) (\w+)\(?)");
regex_global_search(content, regex, [&](const std::smatch &match) {
std::string return_type = match[1].str();
if (return_type == "template") {
/* Matched a template instantiation. */
return;
}
std::string function = match[2].str();
/* Replace all occurrences of the non-namespace specified symbol.
* Reject symbols that contain the target symbol name. */
std::regex regex(R"(([^:\w]))" + function + R"(([\s\(\<]))");
out_content = std::regex_replace(
out_content, regex, "$1" + namespace_name + "::" + function + "$2");
parser.foreach_scope(ScopeType::Namespace, [&](const Scope &scope) {
/* TODO(fclem): This could be supported using multiple passes. */
scope.foreach_match("n", [&](const std::vector<Token> &tokens) {
report_error(ERROR_TOK(tokens[0]), "Nested namespaces are unsupported.");
});
replace_all(out, "namespace " + namespace_name + " {" + content + "}", out_content);
string namespace_prefix = scope.start().prev().full_symbol_name() + "::";
auto process_symbol = [&](const Token &symbol) {
if (symbol.next() == '<') {
/* Template instantiation or specialization. */
return;
}
/* Replace all occurrences of the non-namespace specified symbol. */
scope.foreach_token(Word, [&](const Token &token) {
if (token.str() != symbol.str()) {
return;
}
/* Reject symbols that already have namespace specified. */
if (token.namespace_start() != token) {
return;
}
/* Reject method calls. */
if (token.prev() == '.') {
return;
}
parser.replace(token, namespace_prefix + token.str(), true);
});
};
scope.foreach_function(
[&](bool, Token, Token fn_name, Scope, bool, Scope) { process_symbol(fn_name); });
scope.foreach_struct([&](Token, Token struct_name, Scope) { process_symbol(struct_name); });
Token namespace_tok = scope.start().prev().namespace_start().prev();
if (namespace_tok == Namespace) {
parser.erase(namespace_tok, scope.start());
parser.erase(scope.end());
}
else {
report_error(ERROR_TOK(namespace_tok), "Expected namespace token.");
}
});
return out;
return parser.result_get();
}
/* Needs to run before namespace mutation so that `using` have more precedence. */

View File

@@ -675,6 +675,15 @@ struct Token {
{
return *this != TokenType(type);
}
bool operator==(const Token &other) const
{
return this->index == other.index && this->data == other.data;
}
bool operator!=(const Token &other) const
{
return !(*this == other);
}
};
struct Scope {
@@ -832,11 +841,60 @@ struct Scope {
}
}
void foreach_token(const TokenType token_type, std::function<void(const Token)> callback)
void foreach_token(const TokenType token_type, std::function<void(const Token)> callback) const
{
const char str[2] = {token_type, '\0'};
foreach_match(str, [&](const std::vector<Token> &tokens) { callback(tokens[0]); });
}
/* Run a callback for all existing function scopes. */
void foreach_function(
std::function<void(
bool is_static, Token type, Token name, Scope args, bool is_const, Scope body)> callback)
const
{
foreach_match("m?ww(..)c?{..}", [&](const std::vector<Token> matches) {
callback(matches[0] == Static,
matches[2],
matches[3],
matches[4].scope(),
matches[8] == Const,
matches[10].scope());
});
foreach_match("m?ww::w(..)c?{..}", [&](const std::vector<Token> matches) {
callback(matches[0] == Static,
matches[2],
matches[6],
matches[7].scope(),
matches[11] == Const,
matches[13].scope());
});
foreach_match("m?ww<..>(..)c?{..}", [&](const std::vector<Token> matches) {
callback(matches[0] == Static,
matches[2],
matches[3],
matches[8].scope(),
matches[12] == Const,
matches[14].scope());
});
}
/* Run a callback for all existing struct scopes. */
void foreach_struct(std::function<void(Token struct_tok, Token name, Scope body)> callback) const
{
foreach_match("sw{..}", [&](const std::vector<Token> matches) {
callback(matches[0], matches[1], matches[2].scope());
});
foreach_match("Sw{..}", [&](const std::vector<Token> matches) {
callback(matches[0], matches[1], matches[2].scope());
});
foreach_match("sw<..>{..}", [&](const std::vector<Token> matches) {
callback(matches[0], matches[1], matches[6].scope());
});
foreach_match("Sw<..>{..}", [&](const std::vector<Token> matches) {
callback(matches[0], matches[1], matches[6].scope());
});
}
};
inline Scope Token::scope() const