diff options
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r-- | servers/rendering/shader_language.cpp | 2038 |
1 files changed, 1324 insertions, 714 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 93593effd4..2fa3355d2f 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,26 +30,22 @@ #include "shader_language.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "servers/rendering_server.h" -static bool _is_text_char(CharType c) { - +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(CharType c) { - +static bool _is_number(char32_t c) { return (c >= '0' && c <= '9'); } -static bool _is_hex(CharType c) { - +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] = { "==", "!=", "<", @@ -132,6 +128,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_ISAMPLER3D", "TYPE_USAMPLER3D", "TYPE_SAMPLERCUBE", + "TYPE_SAMPLERCUBEARRAY", "INTERPOLATION_FLAT", "INTERPOLATION_SMOOTH", "CONST", @@ -225,9 +222,8 @@ const char *ShaderLanguage::token_names[TK_MAX] = { }; String ShaderLanguage::get_token_text(Token p_token) { - String name = token_names[p_token.type]; - if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) { + if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_FLOAT_CONSTANT) { name += "(" + rtos(p_token.constant) + ")"; } else if (p_token.type == TK_IDENTIFIER) { name += "(" + String(p_token.text) + ")"; @@ -239,7 +235,6 @@ String ShaderLanguage::get_token_text(Token p_token) { } ShaderLanguage::Token ShaderLanguage::_make_token(TokenType p_type, const StringName &p_text) { - Token tk; tk.type = p_type; tk.text = p_text; @@ -283,6 +278,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_ISAMPLER3D, "isampler3D" }, { TK_TYPE_USAMPLER3D, "usampler3D" }, { TK_TYPE_SAMPLERCUBE, "samplerCube" }, + { TK_TYPE_SAMPLERCUBEARRAY, "samplerCubeArray" }, { TK_INTERPOLATION_FLAT, "flat" }, { TK_INTERPOLATION_SMOOTH, "smooth" }, { TK_CONST, "const" }, @@ -338,13 +334,11 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { }; ShaderLanguage::Token ShaderLanguage::_get_token() { - -#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : CharType(0)) +#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : char32_t(0)) while (true) { char_idx++; switch (GETCHAR(-1)) { - case 0: return _make_token(TK_EOF); case 0xFFFF: @@ -357,7 +351,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { tk_line++; continue; case '/': { - switch (GETCHAR(0)) { case '*': { // block comment @@ -405,7 +398,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { continue; //a comment, continue to next token } break; case '=': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_EQUAL); @@ -494,7 +486,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_OP_BIT_AND); } break; case '|': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_ASSIGN_BIT_OR); @@ -506,7 +497,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } break; case '*': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_ASSIGN_MUL); @@ -514,12 +504,10 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_OP_MUL); } break; case '+': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_ASSIGN_ADD); } else if (GETCHAR(0) == '+') { - char_idx++; return _make_token(TK_OP_INCREMENT); } @@ -527,12 +515,10 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_OP_ADD); } break; case '-': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_ASSIGN_SUB); } else if (GETCHAR(0) == '-') { - char_idx++; return _make_token(TK_OP_DECREMENT); } @@ -540,7 +526,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_OP_SUB); } break; case '%': { - if (GETCHAR(0) == '=') { char_idx++; return _make_token(TK_OP_ASSIGN_MOD); @@ -549,7 +534,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_OP_MOD); } break; 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)))) { @@ -565,38 +549,44 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { while (true) { if (GETCHAR(i) == '.') { - if (period_found || exponent_found || hexa_found || float_suffix_found) + if (period_found || exponent_found || hexa_found || float_suffix_found) { return _make_token(TK_ERROR, "Invalid numeric constant"); + } period_found = true; } else if (GETCHAR(i) == 'x') { - if (hexa_found || str.length() != 1 || str[0] != '0') + if (hexa_found || str.length() != 1 || str[0] != '0') { return _make_token(TK_ERROR, "Invalid numeric constant"); + } hexa_found = true; } else if (GETCHAR(i) == 'e') { - if (hexa_found || exponent_found || float_suffix_found) + if (hexa_found || exponent_found || float_suffix_found) { return _make_token(TK_ERROR, "Invalid numeric constant"); + } exponent_found = true; } else if (GETCHAR(i) == 'f') { - if (hexa_found || exponent_found) + if (hexa_found || exponent_found) { return _make_token(TK_ERROR, "Invalid numeric constant"); + } float_suffix_found = true; } else if (_is_number(GETCHAR(i))) { - if (float_suffix_found) + if (float_suffix_found) { return _make_token(TK_ERROR, "Invalid numeric constant"); + } } else if (hexa_found && _is_hex(GETCHAR(i))) { - } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { - if (sign_found) + if (sign_found) { return _make_token(TK_ERROR, "Invalid numeric constant"); + } sign_found = true; - } else + } else { break; + } - str += CharType(GETCHAR(i)); + str += char32_t(GETCHAR(i)); i++; } - CharType last_char = str[str.length() - 1]; + char32_t last_char = str[str.length() - 1]; if (hexa_found) { //integer(hex) @@ -646,15 +636,16 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { char_idx += str.length(); Token tk; - if (period_found || exponent_found || float_suffix_found) - tk.type = TK_REAL_CONSTANT; - else + if (period_found || exponent_found || float_suffix_found) { + tk.type = TK_FLOAT_CONSTANT; + } else { tk.type = TK_INT_CONSTANT; + } if (hexa_found) { - tk.constant = (double)str.hex_to_int64(true); + tk.constant = (double)str.hex_to_int(true); } else { - tk.constant = str.to_double(); + tk.constant = str.to_float(); } tk.line = tk_line; @@ -672,8 +663,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { String str; while (_is_text_char(GETCHAR(0))) { - - str += CharType(GETCHAR(0)); + str += char32_t(GETCHAR(0)); char_idx++; } @@ -682,9 +672,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { int idx = 0; while (keyword_list[idx].text) { - if (str == keyword_list[idx].text) { - return _make_token(keyword_list[idx].token); } idx++; @@ -695,10 +683,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_IDENTIFIER, str); } - if (GETCHAR(0) > 32) + if (GETCHAR(0) > 32) { return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0)) + ": '" + String::chr(GETCHAR(0)) + "'"); - else + } else { return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0))); + } } break; } @@ -710,7 +699,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } String ShaderLanguage::token_debug(const String &p_code) { - clear(); code = p_code; @@ -719,7 +707,6 @@ String ShaderLanguage::token_debug(const String &p_code) { Token tk = _get_token(); while (tk.type != TK_EOF && tk.type != TK_ERROR) { - output += itos(tk_line) + ": " + get_token_text(tk) + "\n"; tk = _get_token(); } @@ -752,7 +739,6 @@ bool ShaderLanguage::is_token_variable_datatype(TokenType p_type) { } bool ShaderLanguage::is_token_datatype(TokenType p_type) { - return ( p_type == TK_TYPE_VOID || p_type == TK_TYPE_BOOL || @@ -783,31 +769,29 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) { p_type == TK_TYPE_SAMPLER3D || p_type == TK_TYPE_ISAMPLER3D || p_type == TK_TYPE_USAMPLER3D || - p_type == TK_TYPE_SAMPLERCUBE); + p_type == TK_TYPE_SAMPLERCUBE || + p_type == TK_TYPE_SAMPLERCUBEARRAY); } ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) { - return DataType(p_type - TK_TYPE_VOID); } bool ShaderLanguage::is_token_interpolation(TokenType p_type) { - return ( p_type == TK_INTERPOLATION_FLAT || p_type == TK_INTERPOLATION_SMOOTH); } ShaderLanguage::DataInterpolation ShaderLanguage::get_token_interpolation(TokenType p_type) { - - if (p_type == TK_INTERPOLATION_FLAT) + if (p_type == TK_INTERPOLATION_FLAT) { return INTERPOLATION_FLAT; - else + } else { return INTERPOLATION_SMOOTH; + } } bool ShaderLanguage::is_token_precision(TokenType p_type) { - return ( p_type == TK_PRECISION_LOW || p_type == TK_PRECISION_MID || @@ -815,20 +799,23 @@ bool ShaderLanguage::is_token_precision(TokenType p_type) { } ShaderLanguage::DataPrecision ShaderLanguage::get_token_precision(TokenType p_type) { - - if (p_type == TK_PRECISION_LOW) + if (p_type == TK_PRECISION_LOW) { return PRECISION_LOWP; - else if (p_type == TK_PRECISION_HIGH) + } else if (p_type == TK_PRECISION_HIGH) { return PRECISION_HIGHP; - else + } else { return PRECISION_MEDIUMP; + } } String ShaderLanguage::get_precision_name(DataPrecision p_type) { switch (p_type) { - case PRECISION_LOWP: return "lowp"; - case PRECISION_MEDIUMP: return "mediump"; - case PRECISION_HIGHP: return "highp"; + case PRECISION_LOWP: + return "lowp"; + case PRECISION_MEDIUMP: + return "mediump"; + case PRECISION_HIGHP: + return "highp"; default: break; } @@ -836,53 +823,83 @@ String ShaderLanguage::get_precision_name(DataPrecision p_type) { } String ShaderLanguage::get_datatype_name(DataType p_type) { - switch (p_type) { - - case TYPE_VOID: return "void"; - case TYPE_BOOL: return "bool"; - case TYPE_BVEC2: return "bvec2"; - case TYPE_BVEC3: return "bvec3"; - case TYPE_BVEC4: return "bvec4"; - case TYPE_INT: return "int"; - case TYPE_IVEC2: return "ivec2"; - case TYPE_IVEC3: return "ivec3"; - case TYPE_IVEC4: return "ivec4"; - case TYPE_UINT: return "uint"; - case TYPE_UVEC2: return "uvec2"; - case TYPE_UVEC3: return "uvec3"; - case TYPE_UVEC4: return "uvec4"; - case TYPE_FLOAT: return "float"; - case TYPE_VEC2: return "vec2"; - case TYPE_VEC3: return "vec3"; - case TYPE_VEC4: return "vec4"; - case TYPE_MAT2: return "mat2"; - case TYPE_MAT3: return "mat3"; - case TYPE_MAT4: return "mat4"; - case TYPE_SAMPLER2D: return "sampler2D"; - case TYPE_ISAMPLER2D: return "isampler2D"; - case TYPE_USAMPLER2D: return "usampler2D"; - case TYPE_SAMPLER2DARRAY: return "sampler2DArray"; - case TYPE_ISAMPLER2DARRAY: return "isampler2DArray"; - case TYPE_USAMPLER2DARRAY: return "usampler2DArray"; - case TYPE_SAMPLER3D: return "sampler3D"; - case TYPE_ISAMPLER3D: return "isampler3D"; - case TYPE_USAMPLER3D: return "usampler3D"; - case TYPE_SAMPLERCUBE: return "samplerCube"; - case TYPE_STRUCT: return "struct"; - case TYPE_MAX: return "invalid"; + case TYPE_VOID: + return "void"; + case TYPE_BOOL: + return "bool"; + case TYPE_BVEC2: + return "bvec2"; + case TYPE_BVEC3: + return "bvec3"; + case TYPE_BVEC4: + return "bvec4"; + case TYPE_INT: + return "int"; + case TYPE_IVEC2: + return "ivec2"; + case TYPE_IVEC3: + return "ivec3"; + case TYPE_IVEC4: + return "ivec4"; + case TYPE_UINT: + return "uint"; + case TYPE_UVEC2: + return "uvec2"; + case TYPE_UVEC3: + return "uvec3"; + case TYPE_UVEC4: + return "uvec4"; + case TYPE_FLOAT: + return "float"; + case TYPE_VEC2: + return "vec2"; + case TYPE_VEC3: + return "vec3"; + case TYPE_VEC4: + return "vec4"; + case TYPE_MAT2: + return "mat2"; + case TYPE_MAT3: + return "mat3"; + case TYPE_MAT4: + return "mat4"; + case TYPE_SAMPLER2D: + return "sampler2D"; + case TYPE_ISAMPLER2D: + return "isampler2D"; + case TYPE_USAMPLER2D: + return "usampler2D"; + case TYPE_SAMPLER2DARRAY: + return "sampler2DArray"; + case TYPE_ISAMPLER2DARRAY: + return "isampler2DArray"; + case TYPE_USAMPLER2DARRAY: + return "usampler2DArray"; + case TYPE_SAMPLER3D: + return "sampler3D"; + case TYPE_ISAMPLER3D: + return "isampler3D"; + case TYPE_USAMPLER3D: + return "usampler3D"; + case TYPE_SAMPLERCUBE: + return "samplerCube"; + case TYPE_SAMPLERCUBEARRAY: + return "samplerCubeArray"; + case TYPE_STRUCT: + return "struct"; + case TYPE_MAX: + return "invalid"; } return ""; } bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) { - return is_token_datatype(p_type) && p_type != TK_TYPE_VOID; } void ShaderLanguage::clear() { - current_function = StringName(); completion_type = COMPLETION_NONE; @@ -896,6 +913,7 @@ void ShaderLanguage::clear() { char_idx = 0; error_set = false; error_str = ""; + last_const = false; while (nodes) { Node *n = nodes; nodes = nodes->next; @@ -903,18 +921,30 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) { + if (p_function_info.built_ins.has(p_identifier)) { + if (r_data_type) { + *r_data_type = p_function_info.built_ins[p_identifier].type; + } + if (r_is_const) { + *r_is_const = p_function_info.built_ins[p_identifier].constant; + } + if (r_type) { + *r_type = IDENTIFIER_BUILTIN_VAR; + } - if (p_builtin_types.has(p_identifier)) { + return true; + } + if (p_function_info.stage_functions.has(p_identifier)) { if (r_data_type) { - *r_data_type = p_builtin_types[p_identifier].type; + *r_data_type = p_function_info.stage_functions[p_identifier].return_type; } if (r_is_const) { - *r_is_const = p_builtin_types[p_identifier].constant; + *r_is_const = true; } if (r_type) { - *r_type = IDENTIFIER_BUILTIN_VAR; + *r_type = IDENTIFIER_FUNCTION; } return true; @@ -923,7 +953,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea FunctionNode *function = nullptr; while (p_block) { - if (p_block->variables.has(p_identifier)) { if (r_data_type) { *r_data_type = p_block->variables[p_identifier].type; @@ -940,6 +969,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = p_block->variables[p_identifier].struct_name; } + if (r_constant_value) { + *r_constant_value = p_block->variables[p_identifier].value; + } return true; } @@ -968,6 +1000,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = function->arguments[i].type_str; } + if (r_is_const) { + *r_is_const = function->arguments[i].is_const; + } return true; } } @@ -997,22 +1032,33 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea } if (shader->constants.has(p_identifier)) { + if (r_is_const) { + *r_is_const = true; + } if (r_data_type) { *r_data_type = shader->constants[p_identifier].type; } + if (r_array_size) { + *r_array_size = shader->constants[p_identifier].array_size; + } if (r_type) { *r_type = IDENTIFIER_CONSTANT; } if (r_struct_name) { *r_struct_name = shader->constants[p_identifier].type_str; } + if (r_constant_value) { + if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) { + *r_constant_value = shader->constants[p_identifier].initializer->values[0]; + } + } return true; } for (int i = 0; i < shader->functions.size(); i++) { - - if (!shader->functions[i].callable) + if (!shader->functions[i].callable) { continue; + } if (shader->functions[i].name == p_identifier) { if (r_data_type) { @@ -1029,7 +1075,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea } bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type) { - bool valid = false; DataType ret_type = TYPE_VOID; @@ -1062,7 +1107,6 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } break; case OP_NOT: { - DataType na = p_op->arguments[0]->get_datatype(); valid = na == TYPE_BOOL; ret_type = TYPE_BOOL; @@ -1119,13 +1163,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } else if (na == TYPE_FLOAT && nb == TYPE_VEC4) { valid = true; ret_type = TYPE_VEC4; - } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) { + } else if (na == TYPE_FLOAT && nb == TYPE_MAT2) { valid = true; ret_type = TYPE_MAT2; - } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) { + } else if (na == TYPE_FLOAT && nb == TYPE_MAT3) { valid = true; ret_type = TYPE_MAT3; - } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) { + } else if (na == TYPE_FLOAT && nb == TYPE_MAT4) { valid = true; ret_type = TYPE_MAT4; } else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) { @@ -1201,7 +1245,6 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type case OP_ASSIGN_SHIFT_RIGHT: case OP_SHIFT_LEFT: case OP_SHIFT_RIGHT: { - DataType na = p_op->arguments[0]->get_datatype(); DataType nb = p_op->arguments[1]->get_datatype(); @@ -1263,7 +1306,6 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type case OP_ASSIGN_SUB: case OP_ASSIGN_MUL: case OP_ASSIGN_DIV: { - DataType na = p_op->arguments[0]->get_datatype(); DataType nb = p_op->arguments[1]->get_datatype(); @@ -1297,13 +1339,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } else if (na == TYPE_VEC4 && nb == TYPE_FLOAT) { valid = true; ret_type = TYPE_VEC4; - } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT2 && nb == TYPE_VEC2) { + } else if (na == TYPE_MAT2 && nb == TYPE_FLOAT) { valid = true; ret_type = TYPE_MAT2; - } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT3 && nb == TYPE_VEC3) { + } else if (na == TYPE_MAT3 && nb == TYPE_FLOAT) { valid = true; ret_type = TYPE_MAT3; - } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) { + } else if (na == TYPE_MAT4 && nb == TYPE_FLOAT) { valid = true; ret_type = TYPE_MAT4; } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) { @@ -1323,7 +1365,6 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type case OP_BIT_AND: case OP_BIT_OR: case OP_BIT_XOR: { - /* * The bitwise operators and (&), exclusive-or (^), and inclusive-or (|). The operands must be of type * signed or unsigned integers or integer vectors. The operands cannot be vectors of differing size. If @@ -1403,8 +1444,9 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } } - if (r_ret_type) + if (r_ret_type) { *r_ret_type = ret_type; + } return valid; } @@ -2011,6 +2053,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, + { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, @@ -2032,6 +2075,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true }, @@ -2062,6 +2107,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true }, @@ -2093,6 +2139,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true }, @@ -2114,8 +2161,14 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { //array { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, true }, - { nullptr, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false } + // modern functions + { "fma", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, + { "fma", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false }, + { "fma", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false }, + { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false }, + + { nullptr, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false } }; const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { @@ -2124,8 +2177,7 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] { nullptr, 0 } }; -bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) { - +bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) { ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false); Vector<DataType> args; @@ -2142,6 +2194,30 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin int argcount = args.size(); + if (p_function_info.stage_functions.has(name)) { + //stage based function + const StageFunctionInfo &sf = p_function_info.stage_functions[name]; + if (argcount != sf.arguments.size()) { + _set_error(vformat("Invalid number of arguments when calling stage function '%s', which expects %d arguments.", String(name), sf.arguments.size())); + return false; + } + //validate arguments + for (int i = 0; i < argcount; i++) { + if (args[i] != sf.arguments[i].type) { + _set_error(vformat("Invalid argument type when calling stage function '%s', type expected is '%s'.", String(name), String(get_datatype_name(sf.arguments[i].type)))); + return false; + } + } + + if (r_ret_type) { + *r_ret_type = sf.return_type; + } + if (r_ret_type_str) { + *r_ret_type_str = ""; + } + return true; + } + bool failed_builtin = false; bool unsupported_builtin = false; int builtin_idx = 0; @@ -2151,18 +2227,15 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin int idx = 0; while (builtin_func_defs[idx].name) { - if (completion_class != builtin_func_defs[idx].tag) { idx++; continue; } if (name == builtin_func_defs[idx].name) { - failed_builtin = true; bool fail = false; for (int i = 0; i < argcount; i++) { - if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) { //all good, but needs implicit conversion later } else if (args[i] != builtin_func_defs[idx].args[i]) { @@ -2181,20 +2254,18 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin } } - if (!fail && argcount < 4 && builtin_func_defs[idx].args[argcount] != TYPE_VOID) + if (!fail && argcount < 4 && builtin_func_defs[idx].args[argcount] != TYPE_VOID) { fail = true; //make sure the number of arguments matches + } if (!fail) { - //make sure its not an out argument used in the wrong way int outarg_idx = 0; while (builtin_func_out_args[outarg_idx].name) { - if (String(name) == builtin_func_out_args[outarg_idx].name) { int arg_idx = builtin_func_out_args[outarg_idx].argument; if (arg_idx < argcount) { - if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) { _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); return false; @@ -2219,8 +2290,8 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin if (shader->uniforms.has(varname)) { fail = true; } else { - if (p_builtin_types.has(varname)) { - BuiltInInfo info = p_builtin_types[varname]; + if (p_function_info.built_ins.has(varname)) { + BuiltInInfo info = p_function_info.built_ins[varname]; if (info.constant) { fail = true; } @@ -2256,7 +2327,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin const BlockNode *b = p_block; bool valid = false; while (b) { - if (b->variables.has(var_name) || p_builtin_types.has(var_name)) { + if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) { valid = true; break; } @@ -2282,7 +2353,6 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin } //implicitly convert values if possible for (int i = 0; i < argcount; i++) { - if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) { //can't do implicit conversion here continue; @@ -2299,8 +2369,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin p_func->arguments.write[i + 1] = conversion; } - if (r_ret_type) + if (r_ret_type) { *r_ret_type = builtin_func_defs[idx].rettype; + } return true; } @@ -2311,7 +2382,6 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin } if (unsupported_builtin) { - String arglist = ""; for (int i = 0; i < argcount; i++) { if (i > 0) { @@ -2328,13 +2398,17 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin if (failed_builtin) { String err = "Invalid arguments for built-in function: " + String(name) + "("; for (int i = 0; i < argcount; i++) { - if (i > 0) + if (i > 0) { err += ","; + } - if (p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && p_func->arguments[i + 1]->get_datatype() == TYPE_INT && static_cast<ConstantNode *>(p_func->arguments[i + 1])->values[0].sint < 0) { - err += "-"; + String arg_name; + if (args[i] == TYPE_STRUCT) { + arg_name = args2[i]; + } else { + arg_name = get_datatype_name(args[i]); } - err += get_datatype_name(args[i]); + err += arg_name; } err += ")"; _set_error(err); @@ -2347,7 +2421,6 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin BlockNode *block = p_block; while (block) { - if (block->parent_function) { exclude_function = block->parent_function->name; } @@ -2359,10 +2432,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin return false; } - for (int i = 0; i < shader->functions.size(); i++) { + int last_arg_count = 0; + String arg_list = ""; - if (name != shader->functions[i].name) + for (int i = 0; i < shader->functions.size(); i++) { + if (name != shader->functions[i].name) { continue; + } if (!shader->functions[i].callable) { _set_error("Function '" + String(name) + " can't be called from source code."); @@ -2370,30 +2446,53 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin } FunctionNode *pfunc = shader->functions[i].function; + if (arg_list == "") { + for (int j = 0; j < pfunc->arguments.size(); j++) { + if (j > 0) { + arg_list += ", "; + } + String func_arg_name; + if (pfunc->arguments[j].type == TYPE_STRUCT) { + func_arg_name = pfunc->arguments[j].type_str; + } else { + func_arg_name = get_datatype_name(pfunc->arguments[j].type); + } + arg_list += func_arg_name; + } + } - if (pfunc->arguments.size() != args.size()) + if (pfunc->arguments.size() != args.size()) { + last_arg_count = pfunc->arguments.size(); continue; + } bool fail = false; for (int j = 0; j < args.size(); j++) { - if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) { - fail = true; - break; - } if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { //all good, but it needs implicit conversion later - } else if (args[j] != pfunc->arguments[j].type) { + } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str)) { + String func_arg_name; + if (pfunc->arguments[j].type == TYPE_STRUCT) { + func_arg_name = pfunc->arguments[j].type_str; + } else { + func_arg_name = get_datatype_name(pfunc->arguments[j].type); + } + String arg_name; + if (args[j] == TYPE_STRUCT) { + arg_name = args2[j]; + } else { + arg_name = get_datatype_name(args[j]); + } + _set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name)); fail = true; break; } } if (!fail) { - //implicitly convert values if possible for (int k = 0; k < args.size(); k++) { - if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) { //can't do implicit conversion here continue; @@ -2421,6 +2520,12 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin } } + if (last_arg_count > args.size()) { + _set_error(vformat("Too few arguments for \"%s(%s)\" call. Expected at least %s but received %s.", String(name), arg_list, last_arg_count, args.size())); + } else if (last_arg_count < args.size()) { + _set_error(vformat("Too many arguments for \"%s(%s)\" call. Expected at most %s but received %s.", String(name), arg_list, last_arg_count, args.size())); + } + return false; } @@ -2436,8 +2541,7 @@ bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const { return true; } -bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) { - +bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg) { TkPos pos = _get_tkpos(); Token tk = _get_token(); @@ -2448,24 +2552,20 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str _set_tkpos(pos); while (true) { - if (r_complete_arg) { pos = _get_tkpos(); tk = _get_token(); if (tk.type == TK_CURSOR) { - *r_complete_arg = p_func->arguments.size() - 1; } else { - _set_tkpos(pos); } } - Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types); + Node *arg = _parse_and_reduce_expression(p_block, p_function_info); if (!arg) { - return false; } @@ -2474,7 +2574,6 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str tk = _get_token(); if (tk.type == TK_PARENTHESIS_CLOSE) { - return true; } else if (tk.type != TK_COMMA) { // something is broken @@ -2487,7 +2586,6 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str } bool ShaderLanguage::is_token_operator(TokenType p_type) { - return (p_type == TK_OP_EQUAL || p_type == TK_OP_NOT_EQUAL || p_type == TK_OP_LESS || @@ -2526,7 +2624,6 @@ bool ShaderLanguage::is_token_operator(TokenType p_type) { } bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) { - if (p_constant->datatype == p_to_type) { if (p_value) { for (int i = 0; i < p_constant->values.size(); i++) { @@ -2535,13 +2632,11 @@ bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_ty } return true; } else if (p_constant->datatype == TYPE_INT && p_to_type == TYPE_FLOAT) { - if (p_value) { p_value->real = p_constant->values[0].sint; } return true; } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_FLOAT) { - if (p_value) { p_value->real = p_constant->values[0].uint; } @@ -2555,7 +2650,6 @@ bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_ty } return true; } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_INT) { - if (p_constant->values[0].uint > 0x7FFFFFFF) { return false; } @@ -2563,17 +2657,16 @@ bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_ty p_value->sint = p_constant->values[0].uint; } return true; - } else + } else { return false; + } } bool ShaderLanguage::is_scalar_type(DataType p_type) { - return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT; } bool ShaderLanguage::is_sampler_type(DataType p_type) { - return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || p_type == TYPE_USAMPLER2D || @@ -2583,7 +2676,8 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) { p_type == TYPE_SAMPLER3D || p_type == TYPE_ISAMPLER3D || p_type == TYPE_USAMPLER3D || - p_type == TYPE_SAMPLERCUBE; + p_type == TYPE_SAMPLERCUBE || + p_type == TYPE_SAMPLERCUBEARRAY; } Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { @@ -2677,7 +2771,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C case ShaderLanguage::TYPE_USAMPLER2DARRAY: case ShaderLanguage::TYPE_USAMPLER2D: case ShaderLanguage::TYPE_USAMPLER3D: - case ShaderLanguage::TYPE_SAMPLERCUBE: { + case ShaderLanguage::TYPE_SAMPLERCUBE: + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { // Texture types, likely not relevant here. break; } @@ -2696,8 +2791,12 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform &p_uniform) { PropertyInfo pi; switch (p_uniform.type) { - case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break; - case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break; + case ShaderLanguage::TYPE_VOID: + pi.type = Variant::NIL; + break; + case ShaderLanguage::TYPE_BOOL: + pi.type = Variant::BOOL; + break; case ShaderLanguage::TYPE_BVEC2: pi.type = Variant::INT; pi.hint = PROPERTY_HINT_FLAGS; @@ -2728,7 +2827,6 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform case ShaderLanguage::TYPE_UVEC2: case ShaderLanguage::TYPE_UVEC3: case ShaderLanguage::TYPE_UVEC4: { - pi.type = Variant::PACKED_INT32_ARRAY; } break; case ShaderLanguage::TYPE_FLOAT: { @@ -2739,8 +2837,12 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform } } break; - case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break; - case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break; + case ShaderLanguage::TYPE_VEC2: + pi.type = Variant::VECTOR2; + break; + case ShaderLanguage::TYPE_VEC3: + pi.type = Variant::VECTOR3; + break; case ShaderLanguage::TYPE_VEC4: { if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { pi.type = Variant::COLOR; @@ -2748,13 +2850,18 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::PLANE; } } break; - case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break; - case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break; - case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break; + case ShaderLanguage::TYPE_MAT2: + pi.type = Variant::TRANSFORM2D; + break; + case ShaderLanguage::TYPE_MAT3: + pi.type = Variant::BASIS; + break; + case ShaderLanguage::TYPE_MAT4: + pi.type = Variant::TRANSFORM; + break; case ShaderLanguage::TYPE_SAMPLER2D: case ShaderLanguage::TYPE_ISAMPLER2D: case ShaderLanguage::TYPE_USAMPLER2D: { - pi.type = Variant::OBJECT; pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture2D"; @@ -2762,10 +2869,9 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: case ShaderLanguage::TYPE_USAMPLER2DARRAY: { - pi.type = Variant::OBJECT; pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "TextureArray"; + pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: @@ -2774,11 +2880,11 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture3D"; } break; - case ShaderLanguage::TYPE_SAMPLERCUBE: { - + case ShaderLanguage::TYPE_SAMPLERCUBE: + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { pi.type = Variant::OBJECT; pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "CubeMap"; + pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_STRUCT: { // FIXME: Implement this. @@ -2829,6 +2935,7 @@ uint32_t ShaderLanguage::get_type_size(DataType p_type) { case TYPE_ISAMPLER3D: case TYPE_USAMPLER3D: case TYPE_SAMPLERCUBE: + case TYPE_SAMPLERCUBEARRAY: return 4; //not really, but useful for indices case TYPE_STRUCT: // FIXME: Implement. @@ -2840,13 +2947,11 @@ uint32_t ShaderLanguage::get_type_size(DataType p_type) { } void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { - Set<String> kws; int idx = 0; while (keyword_list[idx].text) { - kws.insert(keyword_list[idx].text); idx++; } @@ -2854,7 +2959,6 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { idx = 0; while (builtin_func_defs[idx].name) { - kws.insert(builtin_func_defs[idx].name); idx++; @@ -2866,13 +2970,11 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { } void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) { - Set<String> kws; int idx = 0; while (builtin_func_defs[idx].name) { - kws.insert(builtin_func_defs[idx].name); idx++; @@ -2884,7 +2986,6 @@ void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) { } ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) { - static const DataType scalar_types[] = { TYPE_VOID, TYPE_BOOL, @@ -2947,7 +3048,6 @@ int ShaderLanguage::get_cardinality(DataType p_type) { } bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier) { - identifier = StringName(); TkPos pos = { 0, 0 }; @@ -2961,7 +3061,6 @@ bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionT } if (tk.type == TK_CURSOR) { - completion_type = p_type; completion_line = tk_line; completion_block = p_block; @@ -3003,90 +3102,92 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { return false; } -bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) { - +bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) { if (p_node->type == Node::TYPE_OPERATOR) { - OperatorNode *op = static_cast<OperatorNode *>(p_node); if (op->op == OP_INDEX) { - return _validate_assign(op->arguments[0], p_builtin_types, r_message); + return _validate_assign(op->arguments[0], p_function_info, r_message); } else if (_is_operator_assign(op->op)) { //chained assignment - return _validate_assign(op->arguments[1], p_builtin_types, r_message); + return _validate_assign(op->arguments[1], p_function_info, r_message); } else if (op->op == OP_CALL) { - if (r_message) + if (r_message) { *r_message = RTR("Assignment to function."); + } return false; } } else if (p_node->type == Node::TYPE_MEMBER) { - MemberNode *member = static_cast<MemberNode *>(p_node); if (member->has_swizzling_duplicates) { - if (r_message) + if (r_message) { *r_message = RTR("Swizzling assignment contains duplicates."); + } return false; } - return _validate_assign(member->owner, p_builtin_types, r_message); + return _validate_assign(member->owner, p_function_info, r_message); } else if (p_node->type == Node::TYPE_VARIABLE) { - VariableNode *var = static_cast<VariableNode *>(p_node); if (shader->uniforms.has(var->name)) { - if (r_message) + if (r_message) { *r_message = RTR("Assignment to uniform."); + } return false; } if (shader->varyings.has(var->name) && current_function != String("vertex")) { - if (r_message) + if (r_message) { *r_message = RTR("Varyings can only be assigned in vertex function."); + } return false; } if (shader->constants.has(var->name) || var->is_const) { - if (r_message) + if (r_message) { *r_message = RTR("Constants cannot be modified."); + } return false; } - if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) { + if (!(p_function_info.built_ins.has(var->name) && p_function_info.built_ins[var->name].constant)) { return true; } } else if (p_node->type == Node::TYPE_ARRAY) { - ArrayNode *arr = static_cast<ArrayNode *>(p_node); - if (arr->is_const) { - if (r_message) + if (shader->constants.has(arr->name) || arr->is_const) { + if (r_message) { *r_message = RTR("Constants cannot be modified."); + } return false; } if (shader->varyings.has(arr->name) && current_function != String("vertex")) { - if (r_message) + if (r_message) { *r_message = RTR("Varyings can only be assigned in vertex function."); + } return false; } return true; } - if (r_message) + if (r_message) { *r_message = "Assignment to constant expression."; + } return false; } bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { - ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; if (arg->tex_builtin_check) { @@ -3097,12 +3198,10 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) { return true; } else { - _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting."); return false; } } else { - arg->tex_argument_check = true; arg->tex_argument_filter = p_filter; arg->tex_argument_repeat = p_repeat; @@ -3119,10 +3218,10 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam } ERR_FAIL_V(false); //bug? function not found } + bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { - ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; if (arg->tex_argument_check) { @@ -3137,7 +3236,6 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa return false; } } else { - arg->tex_builtin_check = true; arg->tex_builtin = p_builtin; @@ -3155,14 +3253,143 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa ERR_FAIL_V(false); //bug? function not found } -ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) { +ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) { + DataType type = TYPE_VOID; + String struct_name = ""; + int array_size = 0; + bool auto_size = false; + Token tk = _get_token(); + + if (tk.type == TK_CURLY_BRACKET_OPEN) { + auto_size = true; + } else { + if (shader->structs.has(tk.text)) { + type = TYPE_STRUCT; + struct_name = tk.text; + } else { + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for array"); + return nullptr; + } + type = get_token_datatype(tk.type); + } + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + TkPos pos = _get_tkpos(); + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + array_size = p_array_size; + tk = _get_token(); + } else { + _set_tkpos(pos); + + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + ConstantNode *cnode = (ConstantNode *)n; + if (cnode->values.size() == 1) { + array_size = cnode->values[0].sint; + if (array_size <= 0) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + } else { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return nullptr; + } else { + tk = _get_token(); + } + } + } else { + _set_error("Expected '['"); + return nullptr; + } + + if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) { + String error_str = "Cannot convert from '"; + if (type == TYPE_STRUCT) { + error_str += struct_name; + } else { + error_str += get_datatype_name(type); + } + error_str += "["; + error_str += itos(array_size); + error_str += "]'"; + error_str += " to '"; + if (type == TYPE_STRUCT) { + error_str += p_struct_name; + } else { + error_str += get_datatype_name(p_type); + } + error_str += "["; + error_str += itos(p_array_size); + error_str += "]'"; + _set_error(error_str); + return nullptr; + } + } + + ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); + an->datatype = p_type; + an->struct_name = p_struct_name; + + if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization + while (true) { + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { + return nullptr; + } + + if (p_type != n->get_datatype() || p_struct_name != n->get_datatype_name()) { + _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); + return nullptr; + } + + tk = _get_token(); + if (tk.type == TK_COMMA) { + an->initializer.push_back(n); + } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { + an->initializer.push_back(n); + break; + } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { + an->initializer.push_back(n); + break; + } else { + if (auto_size) { + _set_error("Expected '}' or ','"); + } else { + _set_error("Expected ')' or ','"); + } + return nullptr; + } + } + if (an->initializer.size() != p_array_size) { + _set_error("Array size mismatch"); + return nullptr; + } + } else { + _set_error("Expected array initialization!"); + return nullptr; + } + + return an; +} +ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) { Vector<Expression> expression; //Vector<TokenType> operators; while (true) { - Node *expr = nullptr; TkPos prepos = _get_tkpos(); Token tk = _get_token(); @@ -3173,20 +3400,19 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (tk.type == TK_PARENTHESIS_OPEN) { //handle subexpression - expr = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!expr) + expr = _parse_and_reduce_expression(p_block, p_function_info); + if (!expr) { return nullptr; + } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in expression"); return nullptr; } - } else if (tk.type == TK_REAL_CONSTANT) { - + } else if (tk.type == TK_FLOAT_CONSTANT) { ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; v.real = tk.constant; @@ -3195,7 +3421,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = constant; } else if (tk.type == TK_INT_CONSTANT) { - ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; v.sint = tk.constant; @@ -3204,7 +3429,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = constant; } else if (tk.type == TK_TRUE) { - //handle true constant ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; @@ -3214,7 +3438,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = constant; } else if (tk.type == TK_FALSE) { - //handle false constant ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; @@ -3224,7 +3447,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = constant; } else if (tk.type == TK_TYPE_VOID) { - //make sure void is not used in expression _set_error("Void value not allowed in Expression"); return nullptr; @@ -3235,7 +3457,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons func->op = OP_CONSTRUCT; if (is_token_precision(tk.type)) { - func->return_precision_cache = get_token_precision(tk.type); tk = _get_token(); } @@ -3252,7 +3473,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons int carg = -1; - bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg); + bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg); if (carg >= 0) { completion_type = COMPLETION_CALL_ARGUMENTS; @@ -3262,10 +3483,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons completion_argument = carg; } - if (!ok) + if (!ok) { return nullptr; + } - if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) { + if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) { _set_error("No matching constructor found for: '" + String(funcname->name) + "'"); return nullptr; } @@ -3273,7 +3495,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expr = _reduce_expression(p_block, func); } else if (tk.type == TK_IDENTIFIER) { - _set_tkpos(prepos); StringName identifier; @@ -3290,7 +3511,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (tk.type == TK_PARENTHESIS_OPEN) { - if (struct_init) { //a struct constructor const StringName &name = identifier; @@ -3307,146 +3527,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *nexpr; if (pstruct->members[i]->array_size != 0) { - - DataType type = pstruct->members[i]->get_datatype(); - String struct_name = pstruct->members[i]->struct_name; - int array_size = pstruct->members[i]->array_size; - - DataType type2; - String struct_name2 = ""; - int array_size2 = 0; - - bool auto_size = false; - - tk = _get_token(); - - if (tk.type == TK_CURLY_BRACKET_OPEN) { - auto_size = true; - } else { - - if (shader->structs.has(tk.text)) { - type2 = TYPE_STRUCT; - struct_name2 = tk.text; - } else { - if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); - return nullptr; - } - type2 = get_token_datatype(tk.type); - } - - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - TkPos pos2 = _get_tkpos(); - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - array_size2 = array_size; - tk = _get_token(); - } else { - _set_tkpos(pos2); - - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - ConstantNode *cnode = (ConstantNode *)n; - if (cnode->values.size() == 1) { - array_size2 = cnode->values[0].sint; - if (array_size2 <= 0) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - } else { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - tk = _get_token(); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return nullptr; - } else { - tk = _get_token(); - } - } - } else { - _set_error("Expected '['"); - return nullptr; - } - - if (type != type2 || struct_name != struct_name2 || array_size != array_size2) { - String error_str = "Cannot convert from '"; - if (type2 == TYPE_STRUCT) { - error_str += struct_name2; - } else { - error_str += get_datatype_name(type2); - } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; - if (type == TYPE_STRUCT) { - error_str += struct_name; - } else { - error_str += get_datatype_name(type); - } - error_str += "["; - error_str += itos(array_size); - error_str += "]'"; - _set_error(error_str); - return nullptr; - } - } - - ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); - an->datatype = type; - an->struct_name = struct_name; - - if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization - while (true) { - - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) { - return nullptr; - } - - if (type != n->get_datatype() || struct_name != n->get_datatype_name()) { - _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); - return nullptr; - } - - tk = _get_token(); - if (tk.type == TK_COMMA) { - an->initializer.push_back(n); - continue; - } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { - an->initializer.push_back(n); - break; - } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { - an->initializer.push_back(n); - break; - } else { - if (auto_size) - _set_error("Expected '}' or ','"); - else - _set_error("Expected ')' or ','"); - return nullptr; - } - } - if (an->initializer.size() != array_size) { - _set_error("Array size mismatch"); - return nullptr; - } - } else { - _set_error("Expected array initialization!"); + nexpr = _parse_array_constructor(p_block, p_function_info, pstruct->members[i]->get_datatype(), pstruct->members[i]->struct_name, pstruct->members[i]->array_size); + if (!nexpr) { return nullptr; } - - nexpr = an; } else { - nexpr = _parse_and_reduce_expression(p_block, p_builtin_types); + nexpr = _parse_and_reduce_expression(p_block, p_function_info); if (!nexpr) { return nullptr; } @@ -3488,7 +3574,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons int carg = -1; - bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg); + bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg); // Check if block has a variable with the same name as function to prevent shader crash. ShaderLanguage::BlockNode *bnode = p_block; @@ -3526,10 +3612,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons completion_argument = carg; } - if (!ok) + if (!ok) { return nullptr; + } - if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) { + if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) { _set_error("No matching function found for: '" + String(funcname->name) + "'"); return nullptr; } @@ -3540,14 +3627,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons FunctionNode *call_function = shader->functions[function_index].function; if (call_function) { - //get current base function FunctionNode *base_function = nullptr; { BlockNode *b = p_block; while (b) { - if (b->parent_function) { base_function = b->parent_function; break; @@ -3562,14 +3647,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons for (int i = 0; i < call_function->arguments.size(); i++) { int argidx = i + 1; if (argidx < func->arguments.size()) { - if (call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { + if (call_function->arguments[i].is_const || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { bool error = false; Node *n = func->arguments[argidx]; if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { error = true; } else if (n->type == Node::TYPE_ARRAY) { ArrayNode *an = static_cast<ArrayNode *>(n); - if (an->call_expression != nullptr) { + if (an->call_expression != nullptr || an->is_const) { error = true; } } else if (n->type == Node::TYPE_VARIABLE) { @@ -3578,11 +3663,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons error = true; } else { StringName varname = vn->name; - if (shader->uniforms.has(varname)) { + if (shader->constants.has(varname)) { + error = true; + } else if (shader->uniforms.has(varname)) { error = true; } else { - if (p_builtin_types.has(varname)) { - BuiltInInfo info = p_builtin_types[varname]; + if (p_function_info.built_ins.has(varname)) { + BuiltInInfo info = p_function_info.built_ins[varname]; if (info.constant) { error = true; } @@ -3614,7 +3701,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) { return nullptr; } - } else if (p_builtin_types.has(varname)) { + } else if (p_function_info.built_ins.has(varname)) { //a built-in if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) { return nullptr; @@ -3646,6 +3733,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else { //an identifier + last_const = false; _set_tkpos(pos); DataType data_type; @@ -3669,11 +3757,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } } else { - - if (!_find_identifier(p_block, false, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) { + if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) { _set_error("Unknown identifier in expression: " + String(identifier)); return nullptr; } + last_const = is_const; if (ident_type == IDENTIFIER_FUNCTION) { _set_error("Can't use function as identifier: " + String(identifier)); @@ -3683,28 +3771,44 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *index_expression = nullptr; Node *call_expression = nullptr; + Node *assign_expression = nullptr; if (array_size > 0) { tk = _get_token(); - if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) { - _set_error("Expected '[' or '.'"); + if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) { + _set_error("Expected '[','.' or '='"); return nullptr; } - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (is_const) { + _set_error("Constants cannot be modified."); + return nullptr; + } + if (shader->varyings.has(identifier) && current_function != String("vertex")) { + _set_error("Varyings can only be assigned in vertex function."); + return nullptr; + } + assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + } else if (tk.type == TK_PERIOD) { completion_class = TAG_ARRAY; p_block->block_tag = SubClassTag::TAG_ARRAY; - call_expression = _parse_and_reduce_expression(p_block, p_builtin_types); + call_expression = _parse_and_reduce_expression(p_block, p_function_info); p_block->block_tag = SubClassTag::TAG_GLOBAL; - if (!call_expression) + if (!call_expression) { return nullptr; + } data_type = call_expression->get_datatype(); } else { // indexing - index_expression = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!index_expression) + index_expression = _parse_and_reduce_expression(p_block, p_function_info); + if (!index_expression) { return nullptr; + } if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) { _set_error("Only integer expressions are allowed for indexing"); @@ -3714,7 +3818,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -3737,11 +3841,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons arrname->struct_name = struct_name; arrname->index_expression = index_expression; arrname->call_expression = call_expression; + arrname->assign_expression = assign_expression; arrname->is_const = is_const; expr = arrname; } else { - VariableNode *varname = alloc_node<VariableNode>(); varname->name = identifier; varname->datatype_cache = data_type; @@ -3753,17 +3857,27 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else if (tk.type == TK_OP_ADD) { continue; //this one does nothing } else if (tk.type == TK_OP_SUB || tk.type == TK_OP_NOT || tk.type == TK_OP_BIT_INVERT || tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) { - Expression e; e.is_op = true; switch (tk.type) { - case TK_OP_SUB: e.op = OP_NEGATE; break; - case TK_OP_NOT: e.op = OP_NOT; break; - case TK_OP_BIT_INVERT: e.op = OP_BIT_INVERT; break; - case TK_OP_INCREMENT: e.op = OP_INCREMENT; break; - case TK_OP_DECREMENT: e.op = OP_DECREMENT; break; - default: ERR_FAIL_V(nullptr); + case TK_OP_SUB: + e.op = OP_NEGATE; + break; + case TK_OP_NOT: + e.op = OP_NOT; + break; + case TK_OP_BIT_INVERT: + e.op = OP_BIT_INVERT; + break; + case TK_OP_INCREMENT: + e.op = OP_INCREMENT; + break; + case TK_OP_DECREMENT: + e.op = OP_DECREMENT; + break; + default: + ERR_FAIL_V(nullptr); } expression.push_back(e); @@ -3787,9 +3901,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (tk.type == TK_CURSOR) { //do nothing } else if (tk.type == TK_IDENTIFIER) { - } else if (tk.type == TK_PERIOD) { - DataType dt = expr->get_datatype(); String st = expr->get_datatype_name(); @@ -3844,7 +3956,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC2: case TYPE_UVEC2: case TYPE_VEC2: { - int l = ident.length(); if (l == 1) { member_type = DataType(dt - 1); @@ -3859,9 +3970,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons break; } - const CharType *c = ident.ptr(); + const char32_t *c = ident.ptr(); for (int i = 0; i < l; i++) { - switch (c[i]) { case 'r': case 'g': @@ -3910,7 +4020,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC3: case TYPE_UVEC3: case TYPE_VEC3: { - int l = ident.length(); if (l == 1) { member_type = DataType(dt - 2); @@ -3925,9 +4034,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons break; } - const CharType *c = ident.ptr(); + const char32_t *c = ident.ptr(); for (int i = 0; i < l; i++) { - switch (c[i]) { case 'r': case 'g': @@ -3979,7 +4087,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC4: case TYPE_UVEC4: case TYPE_VEC4: { - int l = ident.length(); if (l == 1) { member_type = DataType(dt - 3); @@ -3994,9 +4101,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons break; } - const CharType *c = ident.ptr(); + const char32_t *c = ident.ptr(); for (int i = 0; i < l; i++) { - switch (c[i]) { case 'r': case 'g': @@ -4075,16 +4181,26 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons mn->has_swizzling_duplicates = repeated; if (array_size > 0) { - tk = _get_token(); - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (last_const) { + last_const = false; + _set_error("Constants cannot be modified."); + return nullptr; + } + Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + mn->assign_expression = assign_expression; + } else if (tk.type == TK_PERIOD) { _set_error("Nested array length() is not yet implemented"); return nullptr; } else if (tk.type == TK_BRACKET_OPEN) { - - Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!index_expression) + Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info); + if (!index_expression) { return nullptr; + } if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) { _set_error("Only integer expressions are allowed for indexing"); @@ -4094,7 +4210,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -4112,7 +4228,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons mn->index_expression = index_expression; } else { - _set_error("Expected '[' or '.'"); + _set_error("Expected '[','.' or '='"); return nullptr; } } @@ -4130,10 +4246,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons */ } else if (tk.type == TK_BRACKET_OPEN) { - - Node *index = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!index) + Node *index = _parse_and_reduce_expression(p_block, p_function_info); + if (!index) { return nullptr; + } if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) { _set_error("Only integer datatypes are allowed for indexing"); @@ -4157,12 +4273,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } switch (expr->get_datatype()) { - case TYPE_BVEC2: member_type = TYPE_BOOL; break; - case TYPE_VEC2: member_type = TYPE_FLOAT; break; - case TYPE_IVEC2: member_type = TYPE_INT; break; - case TYPE_UVEC2: member_type = TYPE_UINT; break; - case TYPE_MAT2: member_type = TYPE_VEC2; break; - default: break; + case TYPE_BVEC2: + member_type = TYPE_BOOL; + break; + case TYPE_VEC2: + member_type = TYPE_FLOAT; + break; + case TYPE_IVEC2: + member_type = TYPE_INT; + break; + case TYPE_UVEC2: + member_type = TYPE_UINT; + break; + case TYPE_MAT2: + member_type = TYPE_VEC2; + break; + default: + break; } break; @@ -4180,12 +4307,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } switch (expr->get_datatype()) { - case TYPE_BVEC3: member_type = TYPE_BOOL; break; - case TYPE_VEC3: member_type = TYPE_FLOAT; break; - case TYPE_IVEC3: member_type = TYPE_INT; break; - case TYPE_UVEC3: member_type = TYPE_UINT; break; - case TYPE_MAT3: member_type = TYPE_VEC3; break; - default: break; + case TYPE_BVEC3: + member_type = TYPE_BOOL; + break; + case TYPE_VEC3: + member_type = TYPE_FLOAT; + break; + case TYPE_IVEC3: + member_type = TYPE_INT; + break; + case TYPE_UVEC3: + member_type = TYPE_UINT; + break; + case TYPE_MAT3: + member_type = TYPE_VEC3; + break; + default: + break; } break; case TYPE_BVEC4: @@ -4202,12 +4340,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } switch (expr->get_datatype()) { - case TYPE_BVEC4: member_type = TYPE_BOOL; break; - case TYPE_VEC4: member_type = TYPE_FLOAT; break; - case TYPE_IVEC4: member_type = TYPE_INT; break; - case TYPE_UVEC4: member_type = TYPE_UINT; break; - case TYPE_MAT4: member_type = TYPE_VEC4; break; - default: break; + case TYPE_BVEC4: + member_type = TYPE_BOOL; + break; + case TYPE_VEC4: + member_type = TYPE_FLOAT; + break; + case TYPE_IVEC4: + member_type = TYPE_INT; + break; + case TYPE_UVEC4: + member_type = TYPE_UINT; + break; + case TYPE_MAT4: + member_type = TYPE_VEC4; + break; + default: + break; } break; default: { @@ -4230,7 +4379,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else if (tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) { - OperatorNode *op = alloc_node<OperatorNode>(); op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT; op->arguments.push_back(expr); @@ -4240,13 +4388,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - if (!_validate_assign(expr, p_builtin_types)) { + if (!_validate_assign(expr, p_function_info)) { _set_error("Invalid use of increment/decrement operator in constant expression."); return nullptr; } expr = op; } else { - _set_tkpos(pos2); break; } @@ -4261,43 +4408,103 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons tk = _get_token(); if (is_token_operator(tk.type)) { - Expression o; o.is_op = true; switch (tk.type) { - - case TK_OP_EQUAL: o.op = OP_EQUAL; break; - case TK_OP_NOT_EQUAL: o.op = OP_NOT_EQUAL; break; - case TK_OP_LESS: o.op = OP_LESS; break; - case TK_OP_LESS_EQUAL: o.op = OP_LESS_EQUAL; break; - case TK_OP_GREATER: o.op = OP_GREATER; break; - case TK_OP_GREATER_EQUAL: o.op = OP_GREATER_EQUAL; break; - case TK_OP_AND: o.op = OP_AND; break; - case TK_OP_OR: o.op = OP_OR; break; - case TK_OP_ADD: o.op = OP_ADD; break; - case TK_OP_SUB: o.op = OP_SUB; break; - case TK_OP_MUL: o.op = OP_MUL; break; - case TK_OP_DIV: o.op = OP_DIV; break; - case TK_OP_MOD: o.op = OP_MOD; break; - case TK_OP_SHIFT_LEFT: o.op = OP_SHIFT_LEFT; break; - case TK_OP_SHIFT_RIGHT: o.op = OP_SHIFT_RIGHT; break; - case TK_OP_ASSIGN: o.op = OP_ASSIGN; break; - case TK_OP_ASSIGN_ADD: o.op = OP_ASSIGN_ADD; break; - case TK_OP_ASSIGN_SUB: o.op = OP_ASSIGN_SUB; break; - case TK_OP_ASSIGN_MUL: o.op = OP_ASSIGN_MUL; break; - case TK_OP_ASSIGN_DIV: o.op = OP_ASSIGN_DIV; break; - case TK_OP_ASSIGN_MOD: o.op = OP_ASSIGN_MOD; break; - case TK_OP_ASSIGN_SHIFT_LEFT: o.op = OP_ASSIGN_SHIFT_LEFT; break; - case TK_OP_ASSIGN_SHIFT_RIGHT: o.op = OP_ASSIGN_SHIFT_RIGHT; break; - case TK_OP_ASSIGN_BIT_AND: o.op = OP_ASSIGN_BIT_AND; break; - case TK_OP_ASSIGN_BIT_OR: o.op = OP_ASSIGN_BIT_OR; break; - case TK_OP_ASSIGN_BIT_XOR: o.op = OP_ASSIGN_BIT_XOR; break; - case TK_OP_BIT_AND: o.op = OP_BIT_AND; break; - case TK_OP_BIT_OR: o.op = OP_BIT_OR; break; - case TK_OP_BIT_XOR: o.op = OP_BIT_XOR; break; - case TK_QUESTION: o.op = OP_SELECT_IF; break; - case TK_COLON: o.op = OP_SELECT_ELSE; break; + case TK_OP_EQUAL: + o.op = OP_EQUAL; + break; + case TK_OP_NOT_EQUAL: + o.op = OP_NOT_EQUAL; + break; + case TK_OP_LESS: + o.op = OP_LESS; + break; + case TK_OP_LESS_EQUAL: + o.op = OP_LESS_EQUAL; + break; + case TK_OP_GREATER: + o.op = OP_GREATER; + break; + case TK_OP_GREATER_EQUAL: + o.op = OP_GREATER_EQUAL; + break; + case TK_OP_AND: + o.op = OP_AND; + break; + case TK_OP_OR: + o.op = OP_OR; + break; + case TK_OP_ADD: + o.op = OP_ADD; + break; + case TK_OP_SUB: + o.op = OP_SUB; + break; + case TK_OP_MUL: + o.op = OP_MUL; + break; + case TK_OP_DIV: + o.op = OP_DIV; + break; + case TK_OP_MOD: + o.op = OP_MOD; + break; + case TK_OP_SHIFT_LEFT: + o.op = OP_SHIFT_LEFT; + break; + case TK_OP_SHIFT_RIGHT: + o.op = OP_SHIFT_RIGHT; + break; + case TK_OP_ASSIGN: + o.op = OP_ASSIGN; + break; + case TK_OP_ASSIGN_ADD: + o.op = OP_ASSIGN_ADD; + break; + case TK_OP_ASSIGN_SUB: + o.op = OP_ASSIGN_SUB; + break; + case TK_OP_ASSIGN_MUL: + o.op = OP_ASSIGN_MUL; + break; + case TK_OP_ASSIGN_DIV: + o.op = OP_ASSIGN_DIV; + break; + case TK_OP_ASSIGN_MOD: + o.op = OP_ASSIGN_MOD; + break; + case TK_OP_ASSIGN_SHIFT_LEFT: + o.op = OP_ASSIGN_SHIFT_LEFT; + break; + case TK_OP_ASSIGN_SHIFT_RIGHT: + o.op = OP_ASSIGN_SHIFT_RIGHT; + break; + case TK_OP_ASSIGN_BIT_AND: + o.op = OP_ASSIGN_BIT_AND; + break; + case TK_OP_ASSIGN_BIT_OR: + o.op = OP_ASSIGN_BIT_OR; + break; + case TK_OP_ASSIGN_BIT_XOR: + o.op = OP_ASSIGN_BIT_XOR; + break; + case TK_OP_BIT_AND: + o.op = OP_BIT_AND; + break; + case TK_OP_BIT_OR: + o.op = OP_BIT_OR; + break; + case TK_OP_BIT_XOR: + o.op = OP_BIT_XOR; + break; + case TK_QUESTION: + o.op = OP_SELECT_IF; + break; + case TK_COLON: + o.op = OP_SELECT_ELSE; + break; default: { _set_error("Invalid token for operator: " + get_token_text(tk)); return nullptr; @@ -4315,16 +4522,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ while (expression.size() > 1) { - int next_op = -1; int min_priority = 0xFFFFF; bool is_unary = false; bool is_ternary = false; for (int i = 0; i < expression.size(); i++) { - if (!expression[i].is_op) { - continue; } @@ -4333,14 +4537,30 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons int priority; switch (expression[i].op) { - case OP_EQUAL: priority = 8; break; - case OP_NOT_EQUAL: priority = 8; break; - case OP_LESS: priority = 7; break; - case OP_LESS_EQUAL: priority = 7; break; - case OP_GREATER: priority = 7; break; - case OP_GREATER_EQUAL: priority = 7; break; - case OP_AND: priority = 12; break; - case OP_OR: priority = 14; break; + case OP_EQUAL: + priority = 8; + break; + case OP_NOT_EQUAL: + priority = 8; + break; + case OP_LESS: + priority = 7; + break; + case OP_LESS_EQUAL: + priority = 7; + break; + case OP_GREATER: + priority = 7; + break; + case OP_GREATER_EQUAL: + priority = 7; + break; + case OP_AND: + priority = 12; + break; + case OP_OR: + priority = 14; + break; case OP_NOT: priority = 3; unary = true; @@ -4349,27 +4569,69 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons priority = 3; unary = true; break; - case OP_ADD: priority = 5; break; - case OP_SUB: priority = 5; break; - case OP_MUL: priority = 4; break; - case OP_DIV: priority = 4; break; - case OP_MOD: priority = 4; break; - case OP_SHIFT_LEFT: priority = 6; break; - case OP_SHIFT_RIGHT: priority = 6; break; - case OP_ASSIGN: priority = 16; break; - case OP_ASSIGN_ADD: priority = 16; break; - case OP_ASSIGN_SUB: priority = 16; break; - case OP_ASSIGN_MUL: priority = 16; break; - case OP_ASSIGN_DIV: priority = 16; break; - case OP_ASSIGN_MOD: priority = 16; break; - case OP_ASSIGN_SHIFT_LEFT: priority = 16; break; - case OP_ASSIGN_SHIFT_RIGHT: priority = 16; break; - case OP_ASSIGN_BIT_AND: priority = 16; break; - case OP_ASSIGN_BIT_OR: priority = 16; break; - case OP_ASSIGN_BIT_XOR: priority = 16; break; - case OP_BIT_AND: priority = 9; break; - case OP_BIT_OR: priority = 11; break; - case OP_BIT_XOR: priority = 10; break; + case OP_ADD: + priority = 5; + break; + case OP_SUB: + priority = 5; + break; + case OP_MUL: + priority = 4; + break; + case OP_DIV: + priority = 4; + break; + case OP_MOD: + priority = 4; + break; + case OP_SHIFT_LEFT: + priority = 6; + break; + case OP_SHIFT_RIGHT: + priority = 6; + break; + case OP_ASSIGN: + priority = 16; + break; + case OP_ASSIGN_ADD: + priority = 16; + break; + case OP_ASSIGN_SUB: + priority = 16; + break; + case OP_ASSIGN_MUL: + priority = 16; + break; + case OP_ASSIGN_DIV: + priority = 16; + break; + case OP_ASSIGN_MOD: + priority = 16; + break; + case OP_ASSIGN_SHIFT_LEFT: + priority = 16; + break; + case OP_ASSIGN_SHIFT_RIGHT: + priority = 16; + break; + case OP_ASSIGN_BIT_AND: + priority = 16; + break; + case OP_ASSIGN_BIT_OR: + priority = 16; + break; + case OP_ASSIGN_BIT_XOR: + priority = 16; + break; + case OP_BIT_AND: + priority = 9; + break; + case OP_BIT_OR: + priority = 11; + break; + case OP_BIT_XOR: + priority = 10; + break; case OP_BIT_INVERT: priority = 3; unary = true; @@ -4410,10 +4672,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons // OK! create operator.. // OK! create operator.. if (is_unary) { - int expr_pos = next_op; while (expression[expr_pos].is_op) { - expr_pos++; if (expr_pos == expression.size()) { //can happen.. @@ -4424,11 +4684,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons //consecutively do unary operators for (int i = expr_pos - 1; i >= next_op; i--) { - OperatorNode *op = alloc_node<OperatorNode>(); op->op = expression[i].op; - if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) { - + if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_function_info)) { _set_error("Can't use increment/decrement operator in constant expression."); return nullptr; } @@ -4438,11 +4696,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expression.write[i].node = op; if (!_validate_operator(op, &op->return_cache)) { - String at; for (int j = 0; j < op->arguments.size(); j++) { - if (j > 0) + if (j > 0) { at += " and "; + } at += get_datatype_name(op->arguments[j]->get_datatype()); } _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at); @@ -4452,7 +4710,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else if (is_ternary) { - if (next_op < 1 || next_op >= (expression.size() - 1)) { _set_error("Parser bug..."); ERR_FAIL_V(nullptr); @@ -4472,11 +4729,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons expression.write[next_op - 1].is_op = false; expression.write[next_op - 1].node = op; if (!_validate_operator(op, &op->return_cache)) { - String at; for (int i = 0; i < op->arguments.size(); i++) { - if (i > 0) + if (i > 0) { at += " and "; + } at += get_datatype_name(op->arguments[i]->get_datatype()); } _set_error("Invalid argument to ternary ?: operator: " + at); @@ -4488,7 +4745,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else { - if (next_op < 1 || next_op >= (expression.size() - 1)) { _set_error("Parser bug..."); ERR_FAIL_V(nullptr); @@ -4498,16 +4754,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->op = expression[next_op].op; if (expression[next_op - 1].is_op) { - _set_error("Parser bug..."); ERR_FAIL_V(nullptr); } if (_is_operator_assign(op->op)) { - String assign_message; - if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) { - + if (!_validate_assign(expression[next_op - 1].node, p_function_info, &assign_message)) { _set_error(assign_message); return nullptr; } @@ -4529,11 +4782,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons //replace all 3 nodes by this operator and make it an expression if (!_validate_operator(op, &op->return_cache)) { - String at; for (int i = 0; i < op->arguments.size(); i++) { - if (i > 0) + if (i > 0) { at += " and "; + } if (op->arguments[i]->get_datatype() == TYPE_STRUCT) { at += op->arguments[i]->get_datatype_name(); } else { @@ -4553,15 +4806,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node) { - - if (p_node->type != Node::TYPE_OPERATOR) + if (p_node->type != Node::TYPE_OPERATOR) { return p_node; + } //for now only reduce simple constructors OperatorNode *op = static_cast<OperatorNode *>(p_node); if (op->op == OP_CONSTRUCT) { - ERR_FAIL_COND_V(op->arguments[0]->type != Node::TYPE_VARIABLE, p_node); DataType type = op->get_datatype(); @@ -4571,7 +4823,6 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha Vector<ConstantNode::Value> values; for (int i = 1; i < op->arguments.size(); i++) { - op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]); if (op->arguments[i]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]); @@ -4581,7 +4832,6 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha values.push_back(cn->values[j]); } } else if (get_scalar_type(cn->datatype) == cn->datatype) { - ConstantNode::Value v; if (!convert_constant(cn, base, &v)) { return p_node; @@ -4625,10 +4875,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha cn->values = values; return cn; } else if (op->op == OP_NEGATE) { - op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]); if (op->arguments[0]->type == Node::TYPE_CONSTANT) { - ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]); DataType base = get_scalar_type(cn->datatype); @@ -4636,7 +4884,6 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha Vector<ConstantNode::Value> values; for (int i = 0; i < cn->values.size(); i++) { - ConstantNode::Value nv; switch (base) { case TYPE_BOOL: { @@ -4667,21 +4914,19 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha return p_node; } -ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) { - - ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types); - if (!expr) //errored +ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info) { + ShaderLanguage::Node *expr = _parse_expression(p_block, p_function_info); + if (!expr) { //errored return nullptr; + } expr = _reduce_expression(p_block, expr); return expr; } -Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) { - +Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one, bool p_can_break, bool p_can_continue) { while (true) { - TkPos pos = _get_tkpos(); Token tk = _get_token(); @@ -4757,7 +5002,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui Node *vardecl = nullptr; while (true) { - if (tk.type != TK_IDENTIFIER) { _set_error("Expected identifier after type"); return ERR_PARSE_ERROR; @@ -4765,7 +5009,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui StringName name = tk.text; ShaderLanguage::IdentifierType itype; - if (_find_identifier(p_block, true, p_builtin_types, name, (ShaderLanguage::DataType *)nullptr, &itype)) { + if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) { if (itype != IDENTIFIER_FUNCTION) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; @@ -4805,18 +5049,53 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui decl.name = name; decl.size = 0U; + pos = _get_tkpos(); tk = _get_token(); if (tk.type == TK_BRACKET_CLOSE) { unknown_size = true; } else { - if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (n) { + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(n); + if (vn) { + ConstantNode::Value v; + DataType data_type; + + _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); + + if (is_const) { + if (data_type == TYPE_INT) { + int32_t value = v.sint; + if (value > 0) { + node->size_expression = n; + decl.size = (uint32_t)value; + } + } else if (data_type == TYPE_UINT) { + uint32_t value = v.uint; + if (value > 0U) { + node->size_expression = n; + decl.size = value; + } + } + } + } + } else if (n->type == Node::TYPE_OPERATOR) { + _set_error("Array size expressions are not yet implemented."); + return ERR_PARSE_ERROR; + } + } + } else if (((int)tk.constant) > 0) { + decl.size = (uint32_t)tk.constant; + } + + if (decl.size == 0U) { _set_error("Expected integer constant > 0 or ']'"); return ERR_PARSE_ERROR; } - - decl.size = ((uint32_t)tk.constant); tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { @@ -4830,7 +5109,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { - if (RenderingServer::get_singleton()->is_low_end()) { _set_error("Array initialization is supported only on high-end platform!"); return ERR_PARSE_ERROR; @@ -4839,7 +5117,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { - if (unknown_size) { _set_error("Expected '{'"); return ERR_PARSE_ERROR; @@ -4862,7 +5139,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } DataType type2; - String struct_name2 = ""; + StringName struct_name2 = ""; if (shader->structs.has(tk.text)) { type2 = TYPE_STRUCT; @@ -4887,7 +5164,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } else { _set_tkpos(pos2); - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); + Node *n = _parse_and_reduce_expression(p_block, p_function_info); if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { _set_error("Expected single integer constant > 0"); return ERR_PARSE_ERROR; @@ -4968,8 +5245,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization while (true) { - - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); + Node *n = _parse_and_reduce_expression(p_block, p_function_info); if (!n) { return ERR_PARSE_ERROR; } @@ -4995,10 +5271,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui decl.initializer.push_back(n); break; } else { - if (curly) + if (curly) { _set_error("Expected '}' or ','"); - else + } else { _set_error("Expected ')' or ','"); + } return ERR_PARSE_ERROR; } } @@ -5016,7 +5293,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui _set_error("Expected array initialization"); return ERR_PARSE_ERROR; } - if (is_const) { + if (node->is_const) { _set_error("Expected initialization of constant"); return ERR_PARSE_ERROR; } @@ -5024,7 +5301,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui node->declarations.push_back(decl); } else if (tk.type == TK_OP_ASSIGN) { - VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); if (is_struct) { node->struct_name = struct_name; @@ -5041,15 +5317,23 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui decl.initializer = nullptr; //variable created with assignment! must parse an expression - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { return ERR_PARSE_ERROR; + } if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { _set_error("Expected constant expression after '='"); return ERR_PARSE_ERROR; } decl.initializer = n; + if (n->type == Node::TYPE_CONSTANT) { + ConstantNode *const_node = static_cast<ConstantNode *>(n); + if (const_node && const_node->values.size() == 1) { + var.value = const_node->values[0]; + } + } + if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) { _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'"); return ERR_PARSE_ERROR; @@ -5100,7 +5384,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui //a sub block, just because.. BlockNode *block = alloc_node<BlockNode>(); block->parent_block = p_block; - if (_parse_block(block, p_builtin_types, false, p_can_break, p_can_continue) != OK) { + if (_parse_block(block, p_function_info, false, p_can_break, p_can_continue) != OK) { return ERR_PARSE_ERROR; } p_block->statements.push_back(block); @@ -5114,9 +5398,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui ControlFlowNode *cf = alloc_node<ControlFlowNode>(); cf->flow_op = FLOW_OP_IF; - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { return ERR_PARSE_ERROR; + } if (n->get_datatype() != TYPE_BOOL) { _set_error("Expected boolean expression"); @@ -5135,24 +5420,23 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue); - if (err) + Error err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue); + if (err) { return err; + } pos = _get_tkpos(); tk = _get_token(); if (tk.type == TK_CF_ELSE) { - block = alloc_node<BlockNode>(); block->parent_block = p_block; cf->blocks.push_back(block); - err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue); + err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue); } else { _set_tkpos(pos); //rollback } } else if (tk.type == TK_CF_SWITCH) { - if (RenderingServer::get_singleton()->is_low_end()) { _set_error("\"switch\" operator is supported only on high-end platform!"); return ERR_PARSE_ERROR; @@ -5166,9 +5450,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } ControlFlowNode *cf = alloc_node<ControlFlowNode>(); cf->flow_op = FLOW_OP_SWITCH; - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { return ERR_PARSE_ERROR; + } if (n->get_datatype() != TYPE_INT) { _set_error("Expected integer expression"); return ERR_PARSE_ERROR; @@ -5193,7 +5478,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui int prev_type = TK_CF_CASE; while (true) { // Go-through multiple cases. - if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) { + if (_parse_block(switch_block, p_function_info, true, true, false) != OK) { return ERR_PARSE_ERROR; } pos = _get_tkpos(); @@ -5217,18 +5502,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i]; if (flow) { if (flow->flow_op == FLOW_OP_CASE) { - ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]); - if (!n2) { - return ERR_PARSE_ERROR; - } - if (n2->values.empty()) { - return ERR_PARSE_ERROR; - } - if (constants.has(n2->values[0].sint)) { - _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'"); - return ERR_PARSE_ERROR; + if (flow->expressions[0]->type == Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]); + if (!cn || cn->values.is_empty()) { + return ERR_PARSE_ERROR; + } + if (constants.has(cn->values[0].sint)) { + _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(cn->values[0].sint); + } else if (flow->expressions[0]->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]); + if (!vn) { + return ERR_PARSE_ERROR; + } + ConstantNode::Value v; + _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v); + if (constants.has(v.sint)) { + _set_error("Duplicated case label: '" + itos(v.sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(v.sint); } - constants.insert(n2->values[0].sint); } else if (flow->flow_op == FLOW_OP_DEFAULT) { continue; } else { @@ -5264,12 +5560,38 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui tk = _get_token(); } + Node *n = nullptr; + if (tk.type != TK_INT_CONSTANT) { - _set_error("Expected integer constant"); - return ERR_PARSE_ERROR; - } + bool correct_constant_expression = false; + DataType data_type; + + if (tk.type == TK_IDENTIFIER) { + bool is_const; + _find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const); + if (is_const) { + if (data_type == TYPE_INT) { + correct_constant_expression = true; + } + } + } + if (!correct_constant_expression) { + _set_error("Expected integer constant"); + return ERR_PARSE_ERROR; + } + + VariableNode *vn = alloc_node<VariableNode>(); + vn->name = tk.text; + n = vn; + } else { + ConstantNode::Value v; + v.sint = (int)tk.constant * sign; - int constant = (int)tk.constant * sign; + ConstantNode *cn = alloc_node<ConstantNode>(); + cn->values.push_back(v); + cn->datatype = TYPE_INT; + n = cn; + } tk = _get_token(); @@ -5281,12 +5603,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui ControlFlowNode *cf = alloc_node<ControlFlowNode>(); cf->flow_op = FLOW_OP_CASE; - ConstantNode *n = alloc_node<ConstantNode>(); - ConstantNode::Value v; - v.sint = constant; - n->values.push_back(v); - n->datatype = TYPE_INT; - BlockNode *case_block = alloc_node<BlockNode>(); case_block->block_type = BlockNode::BLOCK_TYPE_CASE; case_block->parent_block = p_block; @@ -5294,14 +5610,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->blocks.push_back(case_block); p_block->statements.push_back(cf); - Error err = _parse_block(case_block, p_builtin_types, false, true, false); - if (err) + Error err = _parse_block(case_block, p_function_info, false, true, false); + if (err) { return err; + } return OK; } else if (tk.type == TK_CF_DEFAULT) { - if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) { _set_tkpos(pos); return OK; @@ -5328,9 +5644,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->blocks.push_back(default_block); p_block->statements.push_back(cf); - Error err = _parse_block(default_block, p_builtin_types, false, true, false); - if (err) + Error err = _parse_block(default_block, p_function_info, false, true, false); + if (err) { return err; + } return OK; @@ -5341,13 +5658,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui BlockNode *do_block = nullptr; if (is_do) { - do_block = alloc_node<BlockNode>(); do_block->parent_block = p_block; - Error err = _parse_block(do_block, p_builtin_types, true, true, true); - if (err) + Error err = _parse_block(do_block, p_function_info, true, true, true); + if (err) { return err; + } tk = _get_token(); if (tk.type != TK_CF_WHILE) { @@ -5368,9 +5685,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } else { cf->flow_op = FLOW_OP_WHILE; } - Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!n) + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { return ERR_PARSE_ERROR; + } tk = _get_token(); if (tk.type != TK_PARENTHESIS_CLOSE) { @@ -5384,11 +5702,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_builtin_types, true, true, true); - if (err) + Error err = _parse_block(block, p_function_info, true, true, true); + if (err) { return err; + } } else { - cf->expressions.push_back(n); cf->blocks.push_back(do_block); p_block->statements.push_back(cf); @@ -5415,13 +5733,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui init_block->parent_block = p_block; init_block->single_statement = true; cf->blocks.push_back(init_block); - if (_parse_block(init_block, p_builtin_types, true, false, false) != OK) { + 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_builtin_types); - if (!n) + 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("Middle expression is expected to be boolean."); @@ -5436,9 +5755,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->expressions.push_back(n); - n = _parse_and_reduce_expression(init_block, p_builtin_types); - if (!n) + n = _parse_and_reduce_expression(init_block, p_function_info); + if (!n) { return ERR_PARSE_ERROR; + } cf->expressions.push_back(n); @@ -5453,14 +5773,20 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui cf->blocks.push_back(block); p_block->statements.push_back(cf); - Error err = _parse_block(block, p_builtin_types, true, true, true); - if (err) + Error err = _parse_block(block, p_function_info, true, true, true); + if (err) { return err; + } } else if (tk.type == TK_CF_RETURN) { - //check return type BlockNode *b = p_block; + + if (b && b->parent_function && (b->parent_function->name == "vertex" || b->parent_function->name == "fragment" || b->parent_function->name == "light")) { + _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name)); + return ERR_PARSE_ERROR; + } + while (b && !b->parent_function) { b = b->parent_block; } @@ -5483,9 +5809,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } } else { _set_tkpos(pos); //rollback, wants expression - Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!expr) + Node *expr = _parse_and_reduce_expression(p_block, p_function_info); + if (!expr) { return ERR_PARSE_ERROR; + } if (b->parent_function->return_type != expr->get_datatype()) { _set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'"); @@ -5511,7 +5838,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui block = block->parent_block; } } else if (tk.type == TK_CF_DISCARD) { - //check return type BlockNode *b = p_block; while (b && !b->parent_function) { @@ -5539,7 +5865,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui p_block->statements.push_back(flow); } else if (tk.type == TK_CF_BREAK) { - if (!p_can_break) { //all is good _set_error("Breaking is not allowed here"); @@ -5566,7 +5891,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } } else if (tk.type == TK_CF_CONTINUE) { - if (!p_can_continue) { //all is good _set_error("Continuing is not allowed here"); @@ -5585,12 +5909,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui p_block->statements.push_back(flow); } else { - //nothing else, so expression _set_tkpos(pos); //rollback - Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types); - if (!expr) + Node *expr = _parse_and_reduce_expression(p_block, p_function_info); + if (!expr) { return ERR_PARSE_ERROR; + } p_block->statements.push_back(expr); tk = _get_token(); @@ -5600,15 +5924,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } } - if (p_just_one) + if (p_just_one) { break; + } } return OK; } String ShaderLanguage::_get_shader_type_list(const Set<String> &p_shader_types) const { - // Return a list of shader types as an human-readable string String valid_types; for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) { @@ -5664,7 +5988,6 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) { } Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) { - Token tk = _get_token(); if (tk.type != TK_SHADER_TYPE) { @@ -5701,13 +6024,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct int instance_index = 0; ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; - while (tk.type != TK_EOF) { + stages = &p_functions; + while (tk.type != TK_EOF) { switch (tk.type) { case TK_RENDER_MODE: { - while (true) { - StringName mode; _get_completable_identifier(nullptr, COMPLETION_RENDER_MODE, mode); @@ -5869,7 +6191,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } break; case TK_GLOBAL: { - tk = _get_token(); if (tk.type != TK_UNIFORM) { _set_error("Expected 'uniform' after 'global'"); @@ -5891,8 +6212,15 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct [[fallthrough]]; case TK_UNIFORM: case TK_VARYING: { - bool uniform = tk.type == TK_UNIFORM; + + if (!uniform) { + if (shader_type_identifier == "particles" || shader_type_identifier == "sky") { + _set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier)); + return ERR_PARSE_ERROR; + } + } + DataPrecision precision = PRECISION_DEFAULT; DataInterpolation interpolation = INTERPOLATION_SMOOTH; DataType type; @@ -5934,7 +6262,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct name = tk.text; - if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) { + if (_find_identifier(nullptr, false, FunctionInfo(), name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -5945,7 +6273,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (uniform) { - if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { //validate global uniform DataType gvtype = global_var_get_type_func(name); @@ -5972,13 +6299,15 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } } else { - if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) { + if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) { _set_error("Uniforms with 'instance' qualifiers can't be of matrix type."); return ERR_PARSE_ERROR; } uniform2.texture_order = -1; - uniform2.order = uniforms++; + if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { + uniform2.order = uniforms++; + } } uniform2.type = type; uniform2.scope = uniform_scope; @@ -6025,7 +6354,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } uniform2.hint = ShaderNode::Uniform::HINT_COLOR; } else if (tk.type == TK_HINT_RANGE) { - uniform2.hint = ShaderNode::Uniform::HINT_RANGE; if (type != TYPE_FLOAT && type != TYPE_INT) { _set_error("Range hint is for float and int only"); @@ -6047,7 +6375,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -6071,7 +6399,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6084,7 +6412,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6104,7 +6432,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } } else if (tk.type == TK_HINT_INSTANCE_INDEX) { - if (custom_instance_index != -1) { _set_error("Can only specify 'instance_index' once."); return ERR_PARSE_ERROR; @@ -6186,10 +6513,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //reset scope for next uniform if (tk.type == TK_OP_ASSIGN) { - - Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>()); - if (!expr) + Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); + if (!expr) { return ERR_PARSE_ERROR; + } if (expr->type != Node::TYPE_CONSTANT) { _set_error("Expected constant expression after '='"); return ERR_PARSE_ERROR; @@ -6215,7 +6542,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } } else { - ShaderNode::Varying varying; varying.type = type; varying.precision = precision; @@ -6281,7 +6607,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct is_struct = true; struct_name = tk.text; } else { - if (!is_token_datatype(tk.type)) { _set_error("Expected constant, function, uniform or varying"); return ERR_PARSE_ERROR; @@ -6313,7 +6638,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) { + if (_find_identifier(nullptr, false, FunctionInfo(), name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -6339,38 +6664,253 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct constant.type_str = struct_name; constant.precision = precision; constant.initializer = nullptr; + constant.array_size = 0; - if (tk.type == TK_OP_ASSIGN) { + bool unknown_size = false; - if (!is_constant) { - _set_error("Expected 'const' keyword before constant definition"); + if (tk.type == TK_BRACKET_OPEN) { + if (RenderingServer::get_singleton()->is_low_end()) { + _set_error("Global const arrays are supported only on high-end platform!"); return ERR_PARSE_ERROR; } - //variable created with assignment! must parse an expression - Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>()); - if (!expr) + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + unknown_size = true; + tk = _get_token(); + } else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) { + constant.array_size = (int)tk.constant; + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); + } else { + _set_error("Expected integer constant > 0 or ']'"); return ERR_PARSE_ERROR; - if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) { - _set_error("Expected constant expression after '='"); + } + } + + if (tk.type == TK_OP_ASSIGN) { + if (!is_constant) { + _set_error("Expected 'const' keyword before constant definition"); return ERR_PARSE_ERROR; } - constant.initializer = static_cast<ConstantNode *>(expr); + if (constant.array_size > 0 || unknown_size) { + bool full_def = false; + + ArrayDeclarationNode::Declaration decl; + decl.name = name; + decl.size = constant.array_size; + + tk = _get_token(); + + if (tk.type != TK_CURLY_BRACKET_OPEN) { + if (unknown_size) { + _set_error("Expected '{'"); + return ERR_PARSE_ERROR; + } + + full_def = true; + + DataPrecision precision2 = PRECISION_DEFAULT; + if (is_token_precision(tk.type)) { + precision2 = get_token_precision(tk.type); + tk = _get_token(); + if (!is_token_nonvoid_datatype(tk.type)) { + _set_error("Expected datatype after precision"); + return ERR_PARSE_ERROR; + } + } + + StringName struct_name2; + DataType type2; + + if (shader->structs.has(tk.text)) { + type2 = TYPE_STRUCT; + struct_name2 = tk.text; + } else { + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for array"); + return ERR_PARSE_ERROR; + } + type2 = get_token_datatype(tk.type); + } + + int array_size2 = 0; + + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + TkPos pos2 = _get_tkpos(); + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + array_size2 = constant.array_size; + tk = _get_token(); + } else { + _set_tkpos(pos2); + + Node *n = _parse_and_reduce_expression(NULL, FunctionInfo()); + if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + + ConstantNode *cnode = (ConstantNode *)n; + if (cnode->values.size() == 1) { + array_size2 = cnode->values[0].sint; + if (array_size2 <= 0) { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + } else { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']"); + return ERR_PARSE_ERROR; + } else { + tk = _get_token(); + } + } + } else { + _set_error("Expected '["); + return ERR_PARSE_ERROR; + } + + if (constant.precision != precision2 || constant.type != type2 || struct_name != struct_name2 || constant.array_size != array_size2) { + String error_str = "Cannot convert from '"; + if (type2 == TYPE_STRUCT) { + error_str += struct_name2; + } else { + if (precision2 != PRECISION_DEFAULT) { + error_str += get_precision_name(precision2); + error_str += " "; + } + error_str += get_datatype_name(type2); + } + error_str += "["; + error_str += itos(array_size2); + error_str += "]'"; + error_str += " to '"; + if (type == TYPE_STRUCT) { + error_str += struct_name; + } else { + if (precision != PRECISION_DEFAULT) { + error_str += get_precision_name(precision); + error_str += " "; + } + error_str += get_datatype_name(type); + } + error_str += "["; + error_str += itos(constant.array_size); + error_str += "]'"; + _set_error(error_str); + return ERR_PARSE_ERROR; + } + } + + bool curly = tk.type == TK_CURLY_BRACKET_OPEN; + + if (unknown_size) { + if (!curly) { + _set_error("Expected '{'"); + return ERR_PARSE_ERROR; + } + } else { + if (full_def) { + if (curly) { + _set_error("Expected '('"); + return ERR_PARSE_ERROR; + } + } + } - if (is_struct) { - if (expr->get_datatype_name() != struct_name) { - _set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + struct_name + "'"); + if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization + while (true) { + Node *n = _parse_and_reduce_expression(NULL, FunctionInfo()); + if (!n) { + return ERR_PARSE_ERROR; + } + + if (n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + _set_error("Expected constant expression"); + return ERR_PARSE_ERROR; + } + + if (constant.type != n->get_datatype() || n->get_datatype_name() != struct_name) { + _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(constant.type)) + "'"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type == TK_COMMA) { + decl.initializer.push_back(n); + continue; + } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) { + decl.initializer.push_back(n); + break; + } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) { + decl.initializer.push_back(n); + break; + } else { + if (curly) + _set_error("Expected '}' or ','"); + else + _set_error("Expected ')' or ','"); + return ERR_PARSE_ERROR; + } + } + if (unknown_size) { + decl.size = decl.initializer.size(); + constant.array_size = decl.initializer.size(); + } else if (decl.initializer.size() != constant.array_size) { + _set_error("Array size mismatch"); + return ERR_PARSE_ERROR; + } + } + + ConstantNode *expr = memnew(ConstantNode); + + expr->datatype = constant.type; + + expr->struct_name = constant.type_str; + + expr->array_size = constant.array_size; + + expr->array_declarations.push_back(decl); + + constant.initializer = static_cast<ConstantNode *>(expr); + } else { + //variable created with assignment! must parse an expression + Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo()); + if (!expr) + return ERR_PARSE_ERROR; + if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) { + _set_error("Expected constant expression after '='"); + return ERR_PARSE_ERROR; + } + + constant.initializer = static_cast<ConstantNode *>(expr); + + if (type != expr->get_datatype() || expr->get_datatype_name() != struct_name) { + _set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(type)) + "'"); return ERR_PARSE_ERROR; } - } else if (type != expr->get_datatype()) { - _set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'"); - return ERR_PARSE_ERROR; } tk = _get_token(); } else { - _set_error("Expected initialization of constant"); - return ERR_PARSE_ERROR; + if (constant.array_size > 0 || unknown_size) { + _set_error("Expected array initialization"); + return ERR_PARSE_ERROR; + } else { + _set_error("Expected initialization of constant"); + return ERR_PARSE_ERROR; + } } shader->constants[name] = constant; @@ -6384,7 +6924,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } name = tk.text; - if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) { + if (_find_identifier(nullptr, false, FunctionInfo(), name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -6407,14 +6947,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct break; } - Map<StringName, BuiltInInfo> builtin_types; + FunctionInfo builtins; if (p_functions.has(name)) { - builtin_types = p_functions[name].built_ins; + builtins = p_functions[name]; } if (p_functions.has("global")) { // Adds global variables: 'TIME' for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) { - builtin_types.insert(E->key(), E->value()); + builtins.built_ins.insert(E->key(), E->value()); } } @@ -6448,15 +6988,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct break; } + bool is_const = false; + if (tk.type == TK_CONST) { + is_const = true; + tk = _get_token(); + } + ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN; if (tk.type == TK_ARG_IN) { qualifier = ARGUMENT_QUALIFIER_IN; tk = _get_token(); } else if (tk.type == TK_ARG_OUT) { + if (is_const) { + _set_error("'out' qualifier cannot be used within a function parameter declared with 'const'."); + return ERR_PARSE_ERROR; + } qualifier = ARGUMENT_QUALIFIER_OUT; tk = _get_token(); } else if (tk.type == TK_ARG_INOUT) { + if (is_const) { + _set_error("'inout' qualifier cannot be used within a function parameter declared with 'const'."); + return ERR_PARSE_ERROR; + } qualifier = ARGUMENT_QUALIFIER_INOUT; tk = _get_token(); } @@ -6523,7 +7077,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct pname = tk.text; ShaderLanguage::IdentifierType itype; - if (_find_identifier(func_node->body, false, builtin_types, pname, (ShaderLanguage::DataType *)nullptr, &itype)) { + if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) { if (itype != IDENTIFIER_FUNCTION) { _set_error("Redefinition of '" + String(pname) + "'"); return ERR_PARSE_ERROR; @@ -6545,6 +7099,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct arg.tex_builtin_check = false; arg.tex_argument_filter = FILTER_DEFAULT; arg.tex_argument_repeat = REPEAT_DEFAULT; + arg.is_const = is_const; func_node->arguments.push_back(arg); @@ -6584,12 +7139,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct current_function = name; - Error err = _parse_block(func_node->body, builtin_types); - if (err) + Error err = _parse_block(func_node->body, builtins); + if (err) { return err; + } if (func_node->return_type != DataType::TYPE_VOID) { - BlockNode *block = func_node->body; if (_find_last_flow_op_in_block(block, FlowOperation::FLOW_OP_RETURN) != OK) { _set_error("Expected at least one return statement in a non-void function."); @@ -6607,7 +7162,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) { - if (p_functions.has("vertex")) { if (p_functions["vertex"].built_ins.has(p_name)) { return true; @@ -6623,11 +7177,15 @@ bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionI return true; } } + if (p_functions.has("compute")) { + if (p_functions["compute"].built_ins.has(p_name)) { + return true; + } + } return false; } Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op) { - bool found = false; for (int i = p_flow->blocks.size() - 1; i >= 0; i--) { @@ -6646,11 +7204,9 @@ Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOper } Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op) { - bool found = false; for (int i = p_block->statements.size() - 1; i >= 0; i--) { - if (p_block->statements[i]->type == Node::TYPE_CONTROL_FLOW) { ControlFlowNode *flow = (ControlFlowNode *)p_block->statements[i]; if (flow->flow_op == p_op) { @@ -6679,16 +7235,17 @@ Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperat // skips over whitespace and /* */ and // comments static int _get_first_ident_pos(const String &p_code) { - int idx = 0; -#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0)) +#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : char32_t(0)) while (true) { if (GETCHAR(0) == '/' && GETCHAR(1) == '/') { idx += 2; while (true) { - if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == 0) { + return 0; + } if (GETCHAR(0) == '\n') { idx++; break; // loop @@ -6698,7 +7255,9 @@ static int _get_first_ident_pos(const String &p_code) { } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') { idx += 2; while (true) { - if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == 0) { + return 0; + } if (GETCHAR(0) == '*' && GETCHAR(1) == '/') { idx += 2; break; // loop @@ -6723,13 +7282,11 @@ static int _get_first_ident_pos(const String &p_code) { } String ShaderLanguage::get_shader_type(const String &p_code) { - bool reading_type = false; String cur_identifier; for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) { - if (p_code[i] == ';') { break; @@ -6751,14 +7308,14 @@ String ShaderLanguage::get_shader_type(const String &p_code) { } } - if (reading_type) + if (reading_type) { return cur_identifier; + } return String(); } Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { - clear(); code = p_code; @@ -6776,7 +7333,6 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi } Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) { - clear(); code = p_code; @@ -6788,7 +7344,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct _parse_shader(p_functions, p_render_modes, p_shader_types); switch (completion_type) { - case COMPLETION_NONE: { //do nothing return OK; @@ -6802,7 +7357,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_STRUCT: { - if (shader->structs.has(completion_struct)) { StructNode *node = shader->structs[completion_struct].shader_struct; for (int i = 0; i < node->members.size(); i++) { @@ -6814,7 +7368,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_MAIN_FUNCTION: { - for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) { ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); @@ -6824,7 +7377,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } break; case COMPLETION_IDENTIFIER: case COMPLETION_FUNCTION_CALL: { - bool comp_ident = completion_type == COMPLETION_IDENTIFIER; Map<String, ScriptCodeCompletionOption::Kind> matches; StringName skip_function; @@ -6834,7 +7386,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct while (block) { if (comp_ident) { for (const Map<StringName, BlockNode::Variable>::Element *E = block->variables.front(); E; E = E->next()) { - if (E->get().line < completion_line) { matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE); } @@ -6882,14 +7433,21 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } for (int i = 0; i < shader->functions.size(); i++) { - if (!shader->functions[i].callable || shader->functions[i].name == skip_function) + if (!shader->functions[i].callable || shader->functions[i].name == skip_function) { continue; + } matches.insert(String(shader->functions[i].name), ScriptCodeCompletionOption::KIND_FUNCTION); } int idx = 0; bool low_end = RenderingServer::get_singleton()->is_low_end(); + if (stages && stages->has(skip_function)) { + for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[skip_function].stage_functions.front(); E; E = E->next()) { + matches.insert(String(E->key()), ScriptCodeCompletionOption::KIND_FUNCTION); + } + } + while (builtin_func_defs[idx].name) { if (low_end && builtin_func_defs[idx].high_end) { idx++; @@ -6926,12 +7484,21 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_CALL_ARGUMENTS: { + StringName block_function; + BlockNode *block = completion_block; + + while (block) { + if (block->parent_function) { + block_function = block->parent_function->name; + } + block = block->parent_block; + } for (int i = 0; i < shader->functions.size(); i++) { - if (!shader->functions[i].callable) + if (!shader->functions[i].callable) { continue; + } if (shader->functions[i].name == completion_function) { - String calltip; calltip += get_datatype_name(shader->functions[i].function->return_type); @@ -6940,14 +7507,18 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += "("; for (int j = 0; j < shader->functions[i].function->arguments.size(); j++) { - - if (j > 0) + if (j > 0) { calltip += ", "; - else + } else { calltip += " "; + } if (j == completion_argument) { - calltip += CharType(0xFFFF); + calltip += char32_t(0xFFFF); + } + + if (shader->functions[i].function->arguments[j].is_const) { + calltip += "const "; } if (shader->functions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) { @@ -6963,12 +7534,13 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += shader->functions[i].function->arguments[j].name; if (j == completion_argument) { - calltip += CharType(0xFFFF); + calltip += char32_t(0xFFFF); } } - if (shader->functions[i].function->arguments.size()) + if (shader->functions[i].function->arguments.size()) { calltip += " "; + } calltip += ")"; r_call_hint = calltip; @@ -6981,8 +7553,46 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct String calltip; bool low_end = RenderingServer::get_singleton()->is_low_end(); - while (builtin_func_defs[idx].name) { + if (stages && stages->has(block_function)) { + for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[block_function].stage_functions.front(); E; E = E->next()) { + if (completion_function == E->key()) { + calltip += get_datatype_name(E->get().return_type); + calltip += " "; + calltip += E->key(); + calltip += "("; + + for (int i = 0; i < E->get().arguments.size(); i++) { + if (i > 0) { + calltip += ", "; + } else { + calltip += " "; + } + + if (i == completion_argument) { + calltip += char32_t(0xFFFF); + } + + calltip += get_datatype_name(E->get().arguments[i].type); + calltip += " "; + calltip += E->get().arguments[i].name; + + if (i == completion_argument) { + calltip += char32_t(0xFFFF); + } + } + + if (E->get().arguments.size()) { + calltip += " "; + } + calltip += ")"; + + r_call_hint = calltip; + return OK; + } + } + } + while (builtin_func_defs[idx].name) { if (low_end && builtin_func_defs[idx].high_end) { idx++; continue; @@ -6999,14 +7609,14 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } if (completion_function == builtin_func_defs[idx].name) { - if (builtin_func_defs[idx].tag != completion_class) { idx++; continue; } - if (calltip.length()) + if (calltip.length()) { calltip += "\n"; + } calltip += get_datatype_name(builtin_func_defs[idx].rettype); calltip += " "; @@ -7014,18 +7624,19 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += "("; bool found_arg = false; - for (int i = 0; i < 4; i++) { - - if (builtin_func_defs[idx].args[i] == TYPE_VOID) + for (int i = 0; i < BuiltinFuncDef::MAX_ARGS - 1; i++) { + if (builtin_func_defs[idx].args[i] == TYPE_VOID) { break; + } - if (i > 0) + if (i > 0) { calltip += ", "; - else + } else { calltip += " "; + } if (i == completion_argument) { - calltip += CharType(0xFFFF); + calltip += char32_t(0xFFFF); } if (out_arg >= 0 && i == out_arg) { @@ -7035,14 +7646,15 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += get_datatype_name(builtin_func_defs[idx].args[i]); if (i == completion_argument) { - calltip += CharType(0xFFFF); + calltip += char32_t(0xFFFF); } found_arg = true; } - if (found_arg) + if (found_arg) { calltip += " "; + } calltip += ")"; } idx++; @@ -7054,7 +7666,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } break; case COMPLETION_INDEX: { - const char colv[4] = { 'r', 'g', 'b', 'a' }; const char coordv[4] = { 'x', 'y', 'z', 'w' }; const char coordt[4] = { 's', 't', 'p', 'q' }; @@ -7073,7 +7684,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct case TYPE_IVEC3: case TYPE_UVEC3: case TYPE_VEC3: { - limit = 3; } break; @@ -7081,13 +7691,18 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct case TYPE_IVEC4: case TYPE_UVEC4: case TYPE_VEC4: { - limit = 4; } break; - case TYPE_MAT2: limit = 2; break; - case TYPE_MAT3: limit = 3; break; - case TYPE_MAT4: limit = 4; break; + case TYPE_MAT2: + limit = 2; + break; + case TYPE_MAT3: + limit = 3; + break; + case TYPE_MAT4: + limit = 4; + break; default: { } } @@ -7105,27 +7720,22 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } String ShaderLanguage::get_error_text() { - return error_str; } int ShaderLanguage::get_error_line() { - return error_line; } ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() { - return shader; } ShaderLanguage::ShaderLanguage() { - nodes = nullptr; completion_class = TAG_GLOBAL; } ShaderLanguage::~ShaderLanguage() { - clear(); } |