summaryrefslogtreecommitdiff
path: root/servers/rendering/shader_language.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r--servers/rendering/shader_language.cpp191
1 files changed, 117 insertions, 74 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 4e07582187..a433c666f3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -35,18 +35,6 @@
#define HAS_WARNING(flag) (warning_flags & flag)
-static bool _is_text_char(char32_t c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
-}
-
-static bool _is_number(char32_t c) {
- return (c >= '0' && c <= '9');
-}
-
-static bool _is_hex(char32_t c) {
- return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
-}
-
String ShaderLanguage::get_operator_text(Operator p_op) {
static const char *op_names[OP_MAX] = { "==",
"!=",
@@ -543,7 +531,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
default: {
char_idx--; //go back one, since we have no idea what this is
- if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
+ if (is_digit(GETCHAR(0)) || (GETCHAR(0) == '.' && is_digit(GETCHAR(1)))) {
// parse number
bool hexa_found = false;
bool period_found = false;
@@ -584,7 +572,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
const char32_t symbol = String::char_lowercase(GETCHAR(i));
bool error = false;
- if (_is_number(symbol)) {
+ if (is_digit(symbol)) {
if (end_suffix_found) {
error = true;
}
@@ -617,8 +605,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
break;
}
}
- } else if (!hexa_found || !_is_hex(symbol)) {
- if (_is_text_char(symbol)) {
+ } else if (!hexa_found || !is_hex_digit(symbol)) {
+ if (is_ascii_identifier_char(symbol)) {
error = true;
} else {
break;
@@ -649,7 +637,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
}
} else if (period_found || exponent_found || float_suffix_found) { // Float
- if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
+ if (exponent_found && (!is_digit(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
}
if (period_found) {
@@ -660,7 +648,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
}
} else {
//checks for eg. "1." or "1.99" notations
- if (last_char != '.' && !_is_number(last_char)) {
+ if (last_char != '.' && !is_digit(last_char)) {
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
}
}
@@ -723,11 +711,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_PERIOD);
}
- if (_is_text_char(GETCHAR(0))) {
+ if (is_ascii_identifier_char(GETCHAR(0))) {
// parse identifier
String str;
- while (_is_text_char(GETCHAR(0))) {
+ while (is_ascii_identifier_char(GETCHAR(0))) {
str += char32_t(GETCHAR(0));
char_idx++;
}
@@ -5208,9 +5196,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
#ifdef DEBUG_ENABLED
if (check_warnings) {
StringName func_name;
+ BlockNode *b = p_block;
- if (p_block && p_block->parent_function) {
- func_name = p_block->parent_function->name;
+ while (b) {
+ if (b->parent_function) {
+ func_name = b->parent_function->name;
+ break;
+ } else {
+ b = b->parent_block;
+ }
}
_parse_used_identifier(identifier, ident_type, func_name);
@@ -5246,21 +5240,32 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.push_back(e);
continue;
} else {
- if (tk.type != TK_SEMICOLON) {
- _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk)));
- return nullptr;
- } else {
-#ifdef DEBUG_ENABLED
- if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
- _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning."));
- }
-#endif // DEBUG_ENABLED
+ bool valid = false;
+ if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION && tk.type == TK_PARENTHESIS_CLOSE) {
+ valid = true;
_set_tkpos(prepos);
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_EMPTY;
expr = func;
}
+ if (!valid) {
+ if (tk.type != TK_SEMICOLON) {
+ _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk)));
+ return nullptr;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
+ _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning."));
+ }
+#endif // DEBUG_ENABLED
+ _set_tkpos(prepos);
+
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_EMPTY;
+ expr = func;
+ }
+ }
}
ERR_FAIL_COND_V(!expr, nullptr);
@@ -6763,14 +6768,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
array_size = 0;
}
- if (tk.type == TK_COMMA) {
- if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) {
- _set_error(vformat("Multiple declarations in '%s' loop are not supported.", "for"));
- return ERR_PARSE_ERROR;
- }
- } else if (tk.type == TK_SEMICOLON) {
+ if (tk.type == TK_SEMICOLON) {
break;
- } else {
+ } else if (tk.type != TK_COMMA) {
_set_expected_error(",", ";");
return ERR_PARSE_ERROR;
}
@@ -7132,43 +7132,35 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
cf->flow_op = FLOW_OP_FOR;
BlockNode *init_block = alloc_node<BlockNode>();
- init_block->block_type = BlockNode::BLOCK_TYPE_FOR;
+ init_block->block_type = BlockNode::BLOCK_TYPE_FOR_INIT;
init_block->parent_block = p_block;
init_block->single_statement = true;
cf->blocks.push_back(init_block);
- if (_parse_block(init_block, p_function_info, true, false, false) != OK) {
- return ERR_PARSE_ERROR;
- }
-
- Node *n = _parse_and_reduce_expression(init_block, p_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
-
- if (n->get_datatype() != TYPE_BOOL) {
- _set_error(RTR("The middle expression is expected to be boolean."));
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_expected_error(";");
- return ERR_PARSE_ERROR;
+ Error err = _parse_block(init_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
- cf->expressions.push_back(n);
-
- n = _parse_and_reduce_expression(init_block, p_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
+ BlockNode *condition_block = alloc_node<BlockNode>();
+ condition_block->block_type = BlockNode::BLOCK_TYPE_FOR_CONDITION;
+ condition_block->parent_block = init_block;
+ condition_block->single_statement = true;
+ condition_block->use_comma_between_statements = true;
+ cf->blocks.push_back(condition_block);
+ err = _parse_block(condition_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
- cf->expressions.push_back(n);
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_expected_error(")");
- return ERR_PARSE_ERROR;
+ BlockNode *expression_block = alloc_node<BlockNode>();
+ expression_block->block_type = BlockNode::BLOCK_TYPE_FOR_EXPRESSION;
+ expression_block->parent_block = init_block;
+ expression_block->single_statement = true;
+ expression_block->use_comma_between_statements = true;
+ cf->blocks.push_back(expression_block);
+ err = _parse_block(expression_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
BlockNode *block = alloc_node<BlockNode>();
@@ -7176,8 +7168,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_function_info, true, true, true);
- if (err) {
+ err = _parse_block(block, p_function_info, true, true, true);
+ if (err != OK) {
return err;
}
@@ -7327,10 +7319,48 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!expr) {
return ERR_PARSE_ERROR;
}
+
+ bool empty = false;
+
+ if (expr->type == Node::TYPE_OPERATOR) {
+ OperatorNode *op = static_cast<OperatorNode *>(expr);
+ if (op->op == OP_EMPTY) {
+ empty = true;
+ }
+ }
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_INIT) {
+ if (!empty && expr->type != BlockNode::TYPE_VARIABLE_DECLARATION) {
+ _set_error(RTR("The left expression is expected to be a variable declaration."));
+ return ERR_PARSE_ERROR;
+ }
+ }
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) {
+ if (!empty && expr->get_datatype() != TYPE_BOOL) {
+ _set_error(RTR("The middle expression is expected to be boolean."));
+ return ERR_PARSE_ERROR;
+ }
+ }
+
p_block->statements.push_back(expr);
tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) {
+ if (tk.type == TK_COMMA) {
+ continue;
+ }
+ if (tk.type != TK_SEMICOLON) {
+ _set_expected_error(",", ";");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION) {
+ if (tk.type == TK_COMMA) {
+ continue;
+ }
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_expected_error(",", ")");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (tk.type != TK_SEMICOLON) {
_set_expected_error(";");
return ERR_PARSE_ERROR;
}
@@ -7470,7 +7500,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
const String smode = String(mode);
- if (shader->render_modes.find(mode) != -1) {
+ if (shader->render_modes.has(mode)) {
_set_error(vformat(RTR("Duplicated render mode: '%s'."), smode));
return ERR_PARSE_ERROR;
}
@@ -7483,7 +7513,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (smode.begins_with(name)) {
if (!info.options.is_empty()) {
- if (info.options.find(smode.substr(name.length() + 1)) != -1) {
+ if (info.options.has(smode.substr(name.length() + 1))) {
found = true;
if (defined_modes.has(name)) {
@@ -7793,7 +7823,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (uniform) {
- if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor.
//validate global uniform
DataType gvtype = global_var_get_type_func(name);
if (gvtype == TYPE_MAX) {
@@ -9054,6 +9084,19 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
} break;
case COMPLETION_MAIN_FUNCTION: {
for (const KeyValue<StringName, FunctionInfo> &E : p_info.functions) {
+ if (!E.value.main_function) {
+ continue;
+ }
+ bool found = false;
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (shader->functions[i].name == E.key) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ continue;
+ }
ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION);
r_options->push_back(option);
}