diff options
Diffstat (limited to 'servers/rendering/shader_preprocessor.cpp')
-rw-r--r-- | servers/rendering/shader_preprocessor.cpp | 214 |
1 files changed, 180 insertions, 34 deletions
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 8755ee61cc..3766477070 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -434,7 +434,12 @@ void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) { return; } - Error error = expand_macros(body, line, body); + Error error = expand_condition(body, line, body); + if (error != OK) { + return; + } + + error = expand_macros(body, line, body); if (error != OK) { return; } @@ -528,7 +533,12 @@ void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) { return; } - Error error = expand_macros(body, line, body); + Error error = expand_condition(body, line, body); + if (error != OK) { + return; + } + + error = expand_macros(body, line, body); if (error != OK) { return; } @@ -777,47 +787,173 @@ void ShaderPreprocessor::expand_output_macros(int p_start, int p_line_number) { add_to_output(line); } -Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) { - Vector<Pair<String, Define *>> active_defines; - active_defines.resize(state->defines.size()); - int index = 0; - for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { - active_defines.set(index++, Pair<String, Define *>(E->key(), E->get())); +Error ShaderPreprocessor::expand_condition(const String &p_string, int p_line, String &r_expanded) { + // Checks bracket count to be even + check the cursor position. + { + int bracket_start_count = 0; + int bracket_end_count = 0; + + for (int i = 0; i < p_string.size(); i++) { + switch (p_string[i]) { + case CURSOR: + state->completion_type = COMPLETION_TYPE_CONDITION; + break; + case '(': + bracket_start_count++; + break; + case ')': + bracket_end_count++; + break; + } + } + if (bracket_start_count > bracket_end_count) { + _set_expected_error(")", p_line); + return FAILED; + } + if (bracket_end_count > bracket_start_count) { + _set_expected_error("(", p_line); + return FAILED; + } } - return expand_macros(p_string, p_line, active_defines, r_expanded); + String result = p_string; + + int index = 0; + int index_start = 0; + int index_end = 0; + + while (find_match(result, "defined", index, index_start)) { + bool open_bracket = false; + bool found_word = false; + bool word_completed = false; + + LocalVector<char32_t> text; + int post_bracket_index = -1; + int size = result.size(); + + for (int i = (index_start - 1); i < size; i++) { + char32_t c = result[i]; + if (c == 0) { + if (found_word) { + word_completed = true; + } + break; + } + char32_t cs[] = { c, '\0' }; + String s = String(cs); + bool is_space = is_char_space(c); + + if (word_completed) { + if (c == ')') { + continue; + } + if (c == '|' || c == '&') { + if (open_bracket) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + break; + } else if (!is_space) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + } else if (is_space) { + if (found_word && !open_bracket) { + index_end = i; + word_completed = true; + } + } else if (c == '(') { + if (open_bracket) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + open_bracket = true; + } else if (c == ')') { + if (open_bracket) { + if (!found_word) { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + open_bracket = false; + post_bracket_index = i + 1; + } else { + index_end = i; + } + word_completed = true; + } else if (is_char_word(c)) { + text.push_back(c); + found_word = true; + } else { + _set_unexpected_token_error(s, p_line); + return FAILED; + } + } + + if (word_completed) { + if (open_bracket) { + _set_expected_error(")", p_line); + return FAILED; + } + if (post_bracket_index != -1) { + index_end = post_bracket_index; + } + + String body = state->defines.has(vector_to_string(text)) ? "true" : "false"; + String temp = result; + + result = result.substr(0, index) + body; + index_start = result.length(); + if (index_end > 0) { + result += temp.substr(index_end); + } + } else { + set_error(RTR("Invalid macro name."), p_line); + return FAILED; + } + } + r_expanded = result; + return OK; } -Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_expanded) { - r_expanded = p_string; - // When expanding macros we must only evaluate them once. - // Later we continue expanding but with the already - // evaluated macros removed. - for (int i = 0; i < p_defines.size(); i++) { - Pair<String, Define *> define_pair = p_defines[i]; - - Error error = expand_macros_once(r_expanded, p_line, define_pair, r_expanded); - if (error != OK) { - return error; +Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) { + String iterative = p_string; + int pass_count = 0; + bool expanded = true; + + while (expanded) { + expanded = false; + + // As long as we find something to expand, keep going. + for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { + if (expand_macros_once(iterative, p_line, E, iterative)) { + expanded = true; + } } - // Remove expanded macro and recursively replace remaining. - p_defines.remove_at(i); - return expand_macros(r_expanded, p_line, p_defines, r_expanded); + pass_count++; + if (pass_count > 50) { + set_error(RTR("Macro expansion limit exceeded."), p_line); + break; + } } + r_expanded = iterative; + + if (!state->error.is_empty()) { + return FAILED; + } return OK; } -Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded) { +bool ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, const RBMap<String, Define *>::Element *p_define_pair, String &r_expanded) { String result = p_line; - const String &key = p_define_pair.first; - const Define *define = p_define_pair.second; + const String &key = p_define_pair->key(); + const Define *define = p_define_pair->value(); int index_start = 0; int index = 0; - while (find_match(result, key, index, index_start)) { + if (find_match(result, key, index, index_start)) { String body = define->body; if (define->arguments.size() > 0) { // Complex macro with arguments. @@ -825,14 +961,14 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu int args_end = p_line.find(")", args_start); if (args_start == -1 || args_end == -1) { set_error(RTR("Missing macro argument parenthesis."), p_line_number); - return FAILED; + return false; } String values = result.substr(args_start + 1, args_end - (args_start + 1)); Vector<String> args = values.split(","); if (args.size() != define->arguments.size()) { set_error(RTR("Invalid macro argument count."), p_line_number); - return FAILED; + return false; } // Insert macro arguments into the body. @@ -854,11 +990,13 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu // Manually reset index_start to where the body value of the define finishes. // This ensures we don't skip another instance of this macro in the string. index_start = index + body.length() + 1; - break; } + + r_expanded = result; + return true; } - r_expanded = result; - return OK; + + return false; } bool ShaderPreprocessor::find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start) { @@ -1064,7 +1202,7 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen switch (pp_state.completion_type) { case COMPLETION_TYPE_DIRECTIVE: { List<String> options; - get_keyword_list(&options, true); + get_keyword_list(&options, true, true); for (const String &E : options) { ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -1083,6 +1221,11 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen } } break; + case COMPLETION_TYPE_CONDITION: { + ScriptLanguage::CodeCompletionOption option("defined", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); + r_completion_options->push_back(option); + + } break; case COMPLETION_TYPE_INCLUDE_PATH: { if (p_include_completion_func && r_completion_options) { p_include_completion_func(r_completion_options); @@ -1096,8 +1239,11 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen return err; } -void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) { +void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords) { r_keywords->push_back("define"); + if (!p_ignore_context_keywords) { + r_keywords->push_back("defined"); + } r_keywords->push_back("elif"); if (p_include_shader_keywords) { r_keywords->push_back("else"); |