Merge pull request #64459 from Chaosus/shader_elif

This commit is contained in:
Yuri Rubinsky 2022-08-19 07:01:22 +03:00 committed by GitHub
commit 35cfaafda8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 45 deletions

View File

@ -349,6 +349,8 @@ void ShaderPreprocessor::process_directive(Tokenizer *p_tokenizer) {
process_ifdef(p_tokenizer);
} else if (directive == "ifndef") {
process_ifndef(p_tokenizer);
} else if (directive == "elif") {
process_elif(p_tokenizer);
} else if (directive == "else") {
process_else(p_tokenizer);
} else if (directive == "endif") {
@ -415,10 +417,62 @@ void ShaderPreprocessor::process_define(Tokenizer *p_tokenizer) {
}
}
void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->current_branch == nullptr || state->current_branch->else_defined) {
set_error(RTR("Unmatched elif."), line);
return;
}
if (state->previous_region != nullptr) {
state->previous_region->to_line = line - 1;
}
String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
if (body.is_empty()) {
set_error(RTR("Missing condition."), line);
return;
}
Error error = expand_macros(body, line, body);
if (error != OK) {
return;
}
Expression expression;
Vector<String> names;
error = expression.parse(body, names);
if (error != OK) {
set_error(expression.get_error_text(), line);
return;
}
Variant v = expression.execute(Array(), nullptr, false);
if (v.get_type() == Variant::NIL) {
set_error(RTR("Condition evaluation error."), line);
return;
}
bool skip = false;
for (int i = 0; i < state->current_branch->conditions.size(); i++) {
if (state->current_branch->conditions[i]) {
skip = true;
break;
}
}
bool success = !skip && v.booleanize();
start_branch_condition(p_tokenizer, success, true);
if (state->save_regions) {
add_region(line + 1, success, state->previous_region->parent);
}
}
void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->skip_stack_else.is_empty()) {
if (state->current_branch == nullptr || state->current_branch->else_defined) {
set_error(RTR("Unmatched else."), line);
return;
}
@ -428,17 +482,14 @@ void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
p_tokenizer->advance('\n');
bool skip = state->skip_stack_else[state->skip_stack_else.size() - 1];
state->skip_stack_else.remove_at(state->skip_stack_else.size() - 1);
Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_filename];
int index = vec.size() - 1;
if (index >= 0) {
SkippedCondition *cond = vec[index];
if (cond->end_line == -1) {
cond->end_line = p_tokenizer->get_line();
bool skip = false;
for (int i = 0; i < state->current_branch->conditions.size(); i++) {
if (state->current_branch->conditions[i]) {
skip = true;
break;
}
}
state->current_branch->else_defined = true;
if (state->save_regions) {
add_region(line + 1, !skip, state->previous_region->parent);
@ -462,16 +513,10 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
state->previous_region = state->previous_region->parent;
}
Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_filename];
int index = vec.size() - 1;
if (index >= 0) {
SkippedCondition *cond = vec[index];
if (cond->end_line == -1) {
cond->end_line = p_tokenizer->get_line();
}
}
p_tokenizer->advance('\n');
state->current_branch = state->current_branch->parent;
state->branches.pop_back();
}
void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
@ -703,24 +748,19 @@ void ShaderPreprocessor::add_region(int p_line, bool p_enabled, Region *p_parent
state->previous_region = &state->regions[region.file].push_back(region)->get();
}
void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success) {
state->condition_depth++;
if (p_success) {
state->skip_stack_else.push_back(true);
void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue) {
if (!p_continue) {
state->condition_depth++;
state->current_branch = &state->branches.push_back(Branch(p_success, state->current_branch))->get();
} else {
SkippedCondition *cond = memnew(SkippedCondition());
cond->start_line = p_tokenizer->get_line();
state->skipped_conditions[state->current_filename].push_back(cond);
state->current_branch->conditions.push_back(p_success);
}
if (!p_success) {
Vector<String> ends;
ends.push_back("elif");
ends.push_back("else");
ends.push_back("endif");
if (next_directive(p_tokenizer, ends) == "else") {
state->skip_stack_else.push_back(false);
} else {
state->skip_stack_else.push_back(true);
}
next_directive(p_tokenizer, ends);
}
}
@ -909,12 +949,6 @@ void ShaderPreprocessor::clear() {
memdelete(E->get());
}
for (const RBMap<String, Vector<SkippedCondition *>>::Element *E = state->skipped_conditions.front(); E; E = E->next()) {
for (SkippedCondition *condition : E->get()) {
memdelete(condition);
}
}
memdelete(state);
}
state_owner = false;
@ -1064,6 +1098,7 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen
void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) {
r_keywords->push_back("define");
r_keywords->push_back("elif");
if (p_include_shader_keywords) {
r_keywords->push_back("else");
}

View File

@ -130,14 +130,23 @@ private:
String body;
};
struct SkippedCondition {
int start_line = -1;
int end_line = -1;
struct Branch {
Vector<bool> conditions;
Branch *parent = nullptr;
bool else_defined = false;
Branch() {}
Branch(bool p_condition, Branch *p_parent) :
parent(p_parent) {
conditions.push_back(p_condition);
}
};
struct State {
RBMap<String, Define *> defines;
Vector<bool> skip_stack_else;
List<Branch> branches;
Branch *current_branch = nullptr;
int condition_depth = 0;
RBSet<String> includes;
List<uint64_t> cyclic_include_hashes; // Holds code hash of includes.
@ -149,7 +158,6 @@ private:
bool save_regions = false;
RBMap<String, List<Region>> regions;
Region *previous_region = nullptr;
RBMap<String, Vector<SkippedCondition *>> skipped_conditions;
bool disabled = false;
CompletionType completion_type = COMPLETION_TYPE_NONE;
HashSet<Ref<ShaderInclude>> shader_includes;
@ -169,6 +177,7 @@ private:
void process_directive(Tokenizer *p_tokenizer);
void process_define(Tokenizer *p_tokenizer);
void process_elif(Tokenizer *p_tokenizer);
void process_else(Tokenizer *p_tokenizer);
void process_endif(Tokenizer *p_tokenizer);
void process_if(Tokenizer *p_tokenizer);
@ -179,7 +188,7 @@ private:
void process_undef(Tokenizer *p_tokenizer);
void add_region(int p_line, bool p_enabled, Region *p_parent_region);
void start_branch_condition(Tokenizer *p_tokenizer, bool p_success);
void start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue = false);
void expand_output_macros(int p_start, int p_line);
Error expand_macros(const String &p_string, int p_line, String &r_result);