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