diff options
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r-- | servers/rendering/shader_language.cpp | 208 |
1 files changed, 131 insertions, 77 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index cb1329d33c..91201b2028 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++; } @@ -5252,21 +5240,34 @@ 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 (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_FOR_INIT && p_block->block_type != BlockNode::BLOCK_TYPE_FOR_CONDITION)) { + 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); @@ -6371,6 +6372,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } bool is_struct = shader->structs.has(tk.text); + bool is_var_init = false; + bool is_condition = false; if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block if (p_just_one) { @@ -6381,6 +6384,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return OK; } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) { + is_var_init = true; + String struct_name = ""; if (is_struct) { struct_name = tk.text; @@ -6490,9 +6495,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun decl.name = name; #ifdef DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) { - if (p_block && p_block->parent_function) { - StringName func_name = p_block->parent_function->name; + if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG) && p_block) { + FunctionNode *parent_function = nullptr; + { + BlockNode *block = p_block; + while (block && !block->parent_function) { + block = block->parent_block; + } + parent_function = block->parent_function; + } + if (parent_function) { + StringName func_name = parent_function->name; if (!used_local_vars.has(func_name)) { used_local_vars.insert(func_name, Map<StringName, Usage>()); @@ -6769,14 +6782,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; } @@ -7138,43 +7146,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>(); @@ -7182,8 +7182,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; } @@ -7333,15 +7333,56 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (!expr) { return ERR_PARSE_ERROR; } + is_condition = expr->type == Node::TYPE_OPERATOR && expr->get_datatype() == TYPE_BOOL; + + if (expr->type == Node::TYPE_OPERATOR) { + OperatorNode *op = static_cast<OperatorNode *>(expr); + if (op->op == OP_EMPTY) { + is_var_init = true; + is_condition = true; + } + } + 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) { + if (!is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); + return ERR_PARSE_ERROR; + } + 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; } } + if (p_block) { + if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_INIT && !is_var_init) { + _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 && !is_condition) { + _set_error(RTR("The middle expression is expected to be a boolean operator.")); + return ERR_PARSE_ERROR; + } + } + if (p_just_one) { break; } @@ -7476,7 +7517,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; } @@ -7489,7 +7530,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)) { @@ -7799,7 +7840,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) { @@ -7830,7 +7871,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (is_sampler_type(type)) { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { - _set_error(vformat(RTR("Uniforms with '%s' qualifiers can't be of sampler type.", "instance"))); + _set_error(vformat(RTR("The '%s' qualifier is not supported for sampler types."), "SCOPE_INSTANCE")); return ERR_PARSE_ERROR; } uniform2.texture_order = texture_uniforms++; @@ -7846,7 +7887,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } else { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) { - _set_error(vformat(RTR("Uniforms with '%s' qualifier can't be of matrix type.", "instance"))); + _set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE")); return ERR_PARSE_ERROR; } uniform2.texture_order = -1; @@ -9060,6 +9101,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); } |