summaryrefslogtreecommitdiff
path: root/servers/rendering/shader_language.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r--servers/rendering/shader_language.cpp1235
1 files changed, 790 insertions, 445 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 93593effd4..99cc76b2e3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -34,22 +34,18 @@
#include "servers/rendering_server.h"
static bool _is_text_char(CharType c) {
-
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static bool _is_number(CharType c) {
-
return (c >= '0' && c <= '9');
}
static bool _is_hex(CharType 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,7 +222,6 @@ 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) {
name += "(" + rtos(p_token.constant) + ")";
@@ -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))
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,32 +549,38 @@ 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));
i++;
@@ -646,13 +636,14 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
char_idx += str.length();
Token tk;
- if (period_found || exponent_found || float_suffix_found)
+ if (period_found || exponent_found || float_suffix_found) {
tk.type = TK_REAL_CONSTANT;
- else
+ } 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();
}
@@ -672,7 +663,6 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
String str;
while (_is_text_char(GETCHAR(0))) {
-
str += CharType(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;
@@ -904,9 +921,7 @@ 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) {
-
if (p_builtin_types.has(p_identifier)) {
-
if (r_data_type) {
*r_data_type = p_builtin_types[p_identifier].type;
}
@@ -923,7 +938,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;
@@ -968,6 +982,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;
}
}
@@ -1000,6 +1017,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
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;
}
@@ -1010,9 +1030,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
}
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 +1049,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 +1081,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;
@@ -1201,7 +1219,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 +1280,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();
@@ -1323,7 +1339,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 +1418,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 +2027,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 +2049,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 +2081,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 +2113,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 },
@@ -2125,7 +2146,6 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
};
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) {
-
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
Vector<DataType> args;
@@ -2151,18 +2171,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 +2198,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;
@@ -2282,7 +2297,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 +2313,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 +2326,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,8 +2342,9 @@ 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 += "-";
@@ -2347,7 +2362,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;
}
@@ -2360,9 +2374,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
for (int i = 0; i < shader->functions.size(); i++) {
-
- if (name != shader->functions[i].name)
+ if (name != shader->functions[i].name) {
continue;
+ }
if (!shader->functions[i].callable) {
_set_error("Function '" + String(name) + " can't be called from source code.");
@@ -2371,8 +2385,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
FunctionNode *pfunc = shader->functions[i].function;
- if (pfunc->arguments.size() != args.size())
+ if (pfunc->arguments.size() != args.size()) {
continue;
+ }
bool fail = false;
@@ -2390,10 +2405,8 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
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;
@@ -2437,7 +2450,6 @@ bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
}
bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
-
TkPos pos = _get_tkpos();
Token tk = _get_token();
@@ -2448,16 +2460,13 @@ 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);
}
}
@@ -2465,7 +2474,6 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str
Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!arg) {
-
return false;
}
@@ -2474,7 +2482,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 +2494,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 +2532,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 +2540,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 +2558,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 +2565,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 +2584,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 +2679,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 +2699,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 +2735,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 +2745,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 +2758,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 +2777,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 +2788,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 +2843,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 +2855,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 +2867,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 +2878,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 +2894,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 +2956,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 +2969,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;
@@ -3004,9 +3011,7 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
}
bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
-
if (p_node->type == Node::TYPE_OPERATOR) {
-
OperatorNode *op = static_cast<OperatorNode *>(p_node);
if (op->op == OP_INDEX) {
@@ -3017,42 +3022,45 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return _validate_assign(op->arguments[1], p_builtin_types, 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);
} 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;
}
@@ -3060,33 +3068,34 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
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++) {
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 +3106,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 +3126,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++) {
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 +3144,6 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
return false;
}
} else {
-
arg->tex_builtin_check = true;
arg->tex_builtin = p_builtin;
@@ -3156,13 +3162,11 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
}
ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
-
Vector<Expression> expression;
//Vector<TokenType> operators;
while (true) {
-
Node *expr = nullptr;
TkPos prepos = _get_tkpos();
Token tk = _get_token();
@@ -3174,19 +3178,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//handle subexpression
expr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!expr)
+ 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) {
-
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
v.real = tk.constant;
@@ -3195,7 +3198,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 +3206,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 +3215,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 +3224,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 +3234,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();
}
@@ -3262,8 +3260,9 @@ 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)) {
_set_error("No matching constructor found for: '" + String(funcname->name) + "'");
@@ -3273,7 +3272,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 +3288,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,7 +3304,6 @@ 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;
@@ -3323,7 +3319,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_CURLY_BRACKET_OPEN) {
auto_size = true;
} else {
-
if (shader->structs.has(tk.text)) {
type2 = TYPE_STRUCT;
struct_name2 = tk.text;
@@ -3406,7 +3401,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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;
@@ -3428,10 +3422,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
an->initializer.push_back(n);
break;
} else {
- if (auto_size)
+ if (auto_size) {
_set_error("Expected '}' or ','");
- else
+ } else {
_set_error("Expected ')' or ','");
+ }
return nullptr;
}
}
@@ -3526,8 +3521,9 @@ 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)) {
_set_error("No matching function found for: '" + String(funcname->name) + "'");
@@ -3540,14 +3536,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 +3556,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,7 +3572,9 @@ 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)) {
@@ -3669,7 +3665,6 @@ 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)) {
_set_error("Unknown identifier in expression: " + String(identifier));
return nullptr;
@@ -3697,14 +3692,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
p_block->block_tag = SubClassTag::TAG_ARRAY;
call_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
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)
+ 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");
@@ -3741,7 +3738,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = arrname;
} else {
-
VariableNode *varname = alloc_node<VariableNode>();
varname->name = identifier;
varname->datatype_cache = data_type;
@@ -3753,17 +3749,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 +3793,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 +3848,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);
@@ -3861,7 +3864,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
const CharType *c = ident.ptr();
for (int i = 0; i < l; i++) {
-
switch (c[i]) {
case 'r':
case 'g':
@@ -3910,7 +3912,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);
@@ -3927,7 +3928,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
const CharType *c = ident.ptr();
for (int i = 0; i < l; i++) {
-
switch (c[i]) {
case 'r':
case 'g':
@@ -3979,7 +3979,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);
@@ -3996,7 +3995,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
const CharType *c = ident.ptr();
for (int i = 0; i < l; i++) {
-
switch (c[i]) {
case 'r':
case 'g':
@@ -4075,16 +4073,15 @@ 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) {
_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)
+ 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");
@@ -4130,10 +4127,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)
+ 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 +4154,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 +4188,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 +4221,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 +4260,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);
@@ -4246,7 +4275,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
expr = op;
} else {
-
_set_tkpos(pos2);
break;
}
@@ -4261,43 +4289,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 +4403,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 +4418,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 +4450,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 +4553,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 +4565,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)) {
-
_set_error("Can't use increment/decrement operator in constant expression.");
return nullptr;
}
@@ -4438,11 +4577,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 +4591,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 +4610,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 +4626,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 +4635,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)) {
-
_set_error(assign_message);
return nullptr;
}
@@ -4529,11 +4663,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 +4687,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 +4704,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 +4713,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 +4756,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 +4765,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: {
@@ -4668,10 +4796,10 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
}
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
+ if (!expr) { //errored
return nullptr;
+ }
expr = _reduce_expression(p_block, expr);
@@ -4679,9 +4807,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_
}
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) {
-
while (true) {
-
TkPos pos = _get_tkpos();
Token tk = _get_token();
@@ -4757,7 +4883,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;
@@ -4810,7 +4935,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
if (tk.type == TK_BRACKET_CLOSE) {
unknown_size = true;
} else {
-
if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
_set_error("Expected integer constant > 0 or ']'");
return ERR_PARSE_ERROR;
@@ -4830,7 +4954,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 +4962,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 +4984,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;
@@ -4968,7 +5090,6 @@ 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);
if (!n) {
return ERR_PARSE_ERROR;
@@ -4995,10 +5116,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;
}
}
@@ -5024,7 +5146,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;
@@ -5042,8 +5163,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
//variable created with assignment! must parse an expression
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
+ 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;
@@ -5115,8 +5237,9 @@ 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)
+ if (!n) {
return ERR_PARSE_ERROR;
+ }
if (n->get_datatype() != TYPE_BOOL) {
_set_error("Expected boolean expression");
@@ -5136,13 +5259,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
p_block->statements.push_back(cf);
Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
- if (err)
+ 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);
@@ -5152,7 +5275,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
_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;
@@ -5167,8 +5289,9 @@ 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)
+ if (!n) {
return ERR_PARSE_ERROR;
+ }
if (n->get_datatype() != TYPE_INT) {
_set_error("Expected integer expression");
return ERR_PARSE_ERROR;
@@ -5295,13 +5418,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
p_block->statements.push_back(cf);
Error err = _parse_block(case_block, p_builtin_types, false, true, false);
- if (err)
+ 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;
@@ -5329,8 +5452,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
p_block->statements.push_back(cf);
Error err = _parse_block(default_block, p_builtin_types, false, true, false);
- if (err)
+ if (err) {
return err;
+ }
return OK;
@@ -5341,13 +5465,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)
+ if (err) {
return err;
+ }
tk = _get_token();
if (tk.type != TK_CF_WHILE) {
@@ -5369,8 +5493,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->flow_op = FLOW_OP_WHILE;
}
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
+ if (!n) {
return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
@@ -5385,10 +5510,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
p_block->statements.push_back(cf);
Error err = _parse_block(block, p_builtin_types, true, true, true);
- if (err)
+ if (err) {
return err;
+ }
} else {
-
cf->expressions.push_back(n);
cf->blocks.push_back(do_block);
p_block->statements.push_back(cf);
@@ -5420,8 +5545,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
Node *n = _parse_and_reduce_expression(init_block, p_builtin_types);
- if (!n)
+ if (!n) {
return ERR_PARSE_ERROR;
+ }
if (n->get_datatype() != TYPE_BOOL) {
_set_error("Middle expression is expected to be boolean.");
@@ -5437,8 +5563,9 @@ 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)
+ if (!n) {
return ERR_PARSE_ERROR;
+ }
cf->expressions.push_back(n);
@@ -5454,13 +5581,19 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
p_block->statements.push_back(cf);
Error err = _parse_block(block, p_builtin_types, true, true, true);
- if (err)
+ 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;
}
@@ -5484,8 +5617,9 @@ 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)
+ 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 +5645,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 +5672,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 +5698,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 +5716,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)
+ if (!expr) {
return ERR_PARSE_ERROR;
+ }
p_block->statements.push_back(expr);
tk = _get_token();
@@ -5600,15 +5731,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 +5795,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) {
@@ -5702,12 +5832,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
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 +5996,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,7 +6017,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
[[fallthrough]];
case TK_UNIFORM:
case TK_VARYING: {
-
bool uniform = tk.type == TK_UNIFORM;
DataPrecision precision = PRECISION_DEFAULT;
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
@@ -5945,7 +6070,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,7 +6096,7 @@ 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;
}
@@ -6025,7 +6149,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");
@@ -6104,7 +6227,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 +6308,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)
+ if (!expr) {
return ERR_PARSE_ERROR;
+ }
if (expr->type != Node::TYPE_CONSTANT) {
_set_error("Expected constant expression after '='");
return ERR_PARSE_ERROR;
@@ -6215,7 +6337,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 +6402,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;
@@ -6339,38 +6459,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);
+ }
- 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 + "'");
+ 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, Map<StringName, BuiltInInfo>());
+ 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 (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
+ while (true) {
+ Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ 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, Map<StringName, BuiltInInfo>());
+ 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;
@@ -6448,15 +6783,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();
}
@@ -6545,6 +6894,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);
@@ -6585,11 +6935,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
current_function = name;
Error err = _parse_block(func_node->body, builtin_types);
- if (err)
+ 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 +6957,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;
@@ -6627,7 +6976,6 @@ bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionI
}
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 +6994,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,7 +7025,6 @@ 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))
@@ -6688,7 +7033,9 @@ static int _get_first_ident_pos(const String &p_code) {
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 +7045,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 +7072,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 +7098,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 +7123,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 +7134,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 +7147,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 +7158,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 +7167,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 +7176,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,8 +7223,9 @@ 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);
}
@@ -6926,12 +7268,11 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
return OK;
} break;
case COMPLETION_CALL_ARGUMENTS: {
-
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,16 +7281,20 @@ 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);
}
+ if (shader->functions[i].function->arguments[j].is_const) {
+ calltip += "const ";
+ }
+
if (shader->functions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
if (shader->functions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
calltip += "out ";
@@ -6967,8 +7312,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
}
}
- if (shader->functions[i].function->arguments.size())
+ if (shader->functions[i].function->arguments.size()) {
calltip += " ";
+ }
calltip += ")";
r_call_hint = calltip;
@@ -6982,7 +7328,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
bool low_end = RenderingServer::get_singleton()->is_low_end();
while (builtin_func_defs[idx].name) {
-
if (low_end && builtin_func_defs[idx].high_end) {
idx++;
continue;
@@ -6999,14 +7344,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 += " ";
@@ -7015,14 +7360,15 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
bool found_arg = false;
for (int i = 0; i < 4; i++) {
-
- if (builtin_func_defs[idx].args[i] == TYPE_VOID)
+ 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);
@@ -7041,8 +7387,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
found_arg = true;
}
- if (found_arg)
+ if (found_arg) {
calltip += " ";
+ }
calltip += ")";
}
idx++;
@@ -7054,7 +7401,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 +7419,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 +7426,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 +7455,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();
}