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.cpp2556
1 files changed, 1433 insertions, 1123 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 33f4999cdf..6f70a55948 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-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -29,24 +29,13 @@
/*************************************************************************/
#include "shader_language.h"
+
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "servers/rendering_server.h"
#define HAS_WARNING(flag) (warning_flags & flag)
-static bool _is_text_char(char32_t c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
-}
-
-static bool _is_number(char32_t c) {
- return (c >= '0' && c <= '9');
-}
-
-static bool _is_hex(char32_t c) {
- return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
-}
-
String ShaderLanguage::get_operator_text(Operator p_op) {
static const char *op_names[OP_MAX] = { "==",
"!=",
@@ -248,92 +237,141 @@ ShaderLanguage::Token ShaderLanguage::_make_token(TokenType p_type, const String
return tk;
}
+enum ContextFlag : uint32_t {
+ CF_UNSPECIFIED = 0U,
+ CF_BLOCK = 1U, // "void test() { <x> }"
+ CF_FUNC_DECL_PARAM_SPEC = 2U, // "void test(<x> int param) {}"
+ CF_FUNC_DECL_PARAM_TYPE = 4U, // "void test(<x> param) {}"
+ CF_IF_DECL = 8U, // "if(<x>) {}"
+ CF_BOOLEAN = 16U, // "bool t = <x>;"
+ CF_GLOBAL_SPACE = 32U, // "struct", "const", "void" etc.
+ CF_DATATYPE = 64U, // "<x> value;"
+ CF_UNIFORM_TYPE = 128U, // "uniform <x> myUniform;"
+ CF_VARYING_TYPE = 256U, // "varying <x> myVarying;"
+ CF_PRECISION_MODIFIER = 512U, // "<x> vec4 a = vec4(0.0, 1.0, 2.0, 3.0);"
+ CF_INTERPOLATION_QUALIFIER = 1024U, // "varying <x> vec3 myColor;"
+ CF_UNIFORM_KEYWORD = 2048U, // "uniform"
+ CF_CONST_KEYWORD = 4096U, // "const"
+ CF_UNIFORM_QUALIFIER = 8192U, // "<x> uniform float t;"
+};
+
+const uint32_t KCF_DATATYPE = CF_BLOCK | CF_GLOBAL_SPACE | CF_DATATYPE | CF_FUNC_DECL_PARAM_TYPE | CF_UNIFORM_TYPE;
+const uint32_t KCF_SAMPLER_DATATYPE = CF_FUNC_DECL_PARAM_TYPE | CF_UNIFORM_TYPE;
+
const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
- { TK_TRUE, "true" },
- { TK_FALSE, "false" },
- { TK_TYPE_VOID, "void" },
- { TK_TYPE_BOOL, "bool" },
- { TK_TYPE_BVEC2, "bvec2" },
- { TK_TYPE_BVEC3, "bvec3" },
- { TK_TYPE_BVEC4, "bvec4" },
- { TK_TYPE_INT, "int" },
- { TK_TYPE_IVEC2, "ivec2" },
- { TK_TYPE_IVEC3, "ivec3" },
- { TK_TYPE_IVEC4, "ivec4" },
- { TK_TYPE_UINT, "uint" },
- { TK_TYPE_UVEC2, "uvec2" },
- { TK_TYPE_UVEC3, "uvec3" },
- { TK_TYPE_UVEC4, "uvec4" },
- { TK_TYPE_FLOAT, "float" },
- { TK_TYPE_VEC2, "vec2" },
- { TK_TYPE_VEC3, "vec3" },
- { TK_TYPE_VEC4, "vec4" },
- { TK_TYPE_MAT2, "mat2" },
- { TK_TYPE_MAT3, "mat3" },
- { TK_TYPE_MAT4, "mat4" },
- { TK_TYPE_SAMPLER2D, "sampler2D" },
- { TK_TYPE_ISAMPLER2D, "isampler2D" },
- { TK_TYPE_USAMPLER2D, "usampler2D" },
- { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" },
- { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" },
- { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" },
- { TK_TYPE_SAMPLER3D, "sampler3D" },
- { 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" },
- { TK_STRUCT, "struct" },
- { TK_PRECISION_LOW, "lowp" },
- { TK_PRECISION_MID, "mediump" },
- { TK_PRECISION_HIGH, "highp" },
- { TK_CF_IF, "if" },
- { TK_CF_ELSE, "else" },
- { TK_CF_FOR, "for" },
- { TK_CF_WHILE, "while" },
- { TK_CF_DO, "do" },
- { TK_CF_SWITCH, "switch" },
- { TK_CF_CASE, "case" },
- { TK_CF_DEFAULT, "default" },
- { TK_CF_BREAK, "break" },
- { TK_CF_CONTINUE, "continue" },
- { TK_CF_RETURN, "return" },
- { TK_CF_DISCARD, "discard" },
- { TK_UNIFORM, "uniform" },
- { TK_INSTANCE, "instance" },
- { TK_GLOBAL, "global" },
- { TK_VARYING, "varying" },
- { TK_ARG_IN, "in" },
- { TK_ARG_OUT, "out" },
- { TK_ARG_INOUT, "inout" },
- { TK_RENDER_MODE, "render_mode" },
- { TK_HINT_WHITE_TEXTURE, "hint_white" },
- { TK_HINT_BLACK_TEXTURE, "hint_black" },
- { TK_HINT_NORMAL_TEXTURE, "hint_normal" },
- { TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal" },
- { TK_HINT_ROUGHNESS_R, "hint_roughness_r" },
- { TK_HINT_ROUGHNESS_G, "hint_roughness_g" },
- { TK_HINT_ROUGHNESS_B, "hint_roughness_b" },
- { TK_HINT_ROUGHNESS_A, "hint_roughness_a" },
- { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray" },
- { TK_HINT_ANISOTROPY_TEXTURE, "hint_anisotropy" },
- { TK_HINT_ALBEDO_TEXTURE, "hint_albedo" },
- { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
- { TK_HINT_COLOR, "hint_color" },
- { TK_HINT_RANGE, "hint_range" },
- { TK_HINT_INSTANCE_INDEX, "instance_index" },
- { TK_FILTER_NEAREST, "filter_nearest" },
- { TK_FILTER_LINEAR, "filter_linear" },
- { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
- { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
- { TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC, "filter_nearest_mipmap_anisotropic" },
- { TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC, "filter_linear_mipmap_anisotropic" },
- { TK_REPEAT_ENABLE, "repeat_enable" },
- { TK_REPEAT_DISABLE, "repeat_disable" },
- { TK_SHADER_TYPE, "shader_type" },
- { TK_ERROR, nullptr }
+ { TK_TRUE, "true", CF_BLOCK | CF_IF_DECL | CF_BOOLEAN, {}, {} },
+ { TK_FALSE, "false", CF_BLOCK | CF_IF_DECL | CF_BOOLEAN, {}, {} },
+
+ // data types
+
+ { TK_TYPE_VOID, "void", CF_GLOBAL_SPACE, {}, {} },
+ { TK_TYPE_BOOL, "bool", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_BVEC2, "bvec2", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_BVEC3, "bvec3", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_BVEC4, "bvec4", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_INT, "int", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_IVEC2, "ivec2", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_IVEC3, "ivec3", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_IVEC4, "ivec4", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_UINT, "uint", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_UVEC2, "uvec2", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_UVEC3, "uvec3", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_UVEC4, "uvec4", KCF_DATATYPE, {}, {} },
+ { TK_TYPE_FLOAT, "float", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_VEC2, "vec2", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_VEC3, "vec3", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_VEC4, "vec4", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_MAT2, "mat2", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_MAT3, "mat3", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_MAT4, "mat4", KCF_DATATYPE | CF_VARYING_TYPE, {}, {} },
+ { TK_TYPE_SAMPLER2D, "sampler2D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_ISAMPLER2D, "isampler2D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_USAMPLER2D, "usampler2D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_SAMPLER3D, "sampler3D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_ISAMPLER3D, "isampler3D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_USAMPLER3D, "usampler3D", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_SAMPLERCUBE, "samplerCube", KCF_SAMPLER_DATATYPE, {}, {} },
+ { TK_TYPE_SAMPLERCUBEARRAY, "samplerCubeArray", KCF_SAMPLER_DATATYPE, {}, {} },
+
+ // interpolation qualifiers
+
+ { TK_INTERPOLATION_FLAT, "flat", CF_INTERPOLATION_QUALIFIER, {}, {} },
+ { TK_INTERPOLATION_SMOOTH, "smooth", CF_INTERPOLATION_QUALIFIER, {}, {} },
+
+ // precision modifiers
+
+ { TK_PRECISION_LOW, "lowp", CF_BLOCK | CF_PRECISION_MODIFIER, {}, {} },
+ { TK_PRECISION_MID, "mediump", CF_BLOCK | CF_PRECISION_MODIFIER, {}, {} },
+ { TK_PRECISION_HIGH, "highp", CF_BLOCK | CF_PRECISION_MODIFIER, {}, {} },
+
+ // global space keywords
+
+ { TK_UNIFORM, "uniform", CF_GLOBAL_SPACE | CF_UNIFORM_KEYWORD, {}, {} },
+ { TK_VARYING, "varying", CF_GLOBAL_SPACE, { "particles", "sky", "fog" }, {} },
+ { TK_CONST, "const", CF_BLOCK | CF_GLOBAL_SPACE | CF_CONST_KEYWORD, {}, {} },
+ { TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} },
+ { TK_SHADER_TYPE, "shader_type", CF_GLOBAL_SPACE, {}, {} },
+ { TK_RENDER_MODE, "render_mode", CF_GLOBAL_SPACE, {}, {} },
+
+ // uniform qualifiers
+
+ { TK_INSTANCE, "instance", CF_GLOBAL_SPACE | CF_UNIFORM_QUALIFIER, {}, {} },
+ { TK_GLOBAL, "global", CF_GLOBAL_SPACE | CF_UNIFORM_QUALIFIER, {}, {} },
+
+ // block keywords
+
+ { TK_CF_IF, "if", CF_BLOCK, {}, {} },
+ { TK_CF_ELSE, "else", CF_BLOCK, {}, {} },
+ { TK_CF_FOR, "for", CF_BLOCK, {}, {} },
+ { TK_CF_WHILE, "while", CF_BLOCK, {}, {} },
+ { TK_CF_DO, "do", CF_BLOCK, {}, {} },
+ { TK_CF_SWITCH, "switch", CF_BLOCK, {}, {} },
+ { TK_CF_CASE, "case", CF_BLOCK, {}, {} },
+ { TK_CF_DEFAULT, "default", CF_BLOCK, {}, {} },
+ { TK_CF_BREAK, "break", CF_BLOCK, {}, {} },
+ { TK_CF_CONTINUE, "continue", CF_BLOCK, {}, {} },
+ { TK_CF_RETURN, "return", CF_BLOCK, {}, {} },
+ { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "fragment" } },
+
+ // function specifier keywords
+
+ { TK_ARG_IN, "in", CF_FUNC_DECL_PARAM_SPEC, {}, {} },
+ { TK_ARG_OUT, "out", CF_FUNC_DECL_PARAM_SPEC, {}, {} },
+ { TK_ARG_INOUT, "inout", CF_FUNC_DECL_PARAM_SPEC, {}, {} },
+
+ // hints
+
+ { TK_HINT_RANGE, "hint_range", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_COLOR, "hint_color", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_INSTANCE_INDEX, "instance_index", CF_UNSPECIFIED, {}, {} },
+
+ // sampler hints
+
+ { TK_HINT_ALBEDO_TEXTURE, "hint_albedo", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_NORMAL_TEXTURE, "hint_normal", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_WHITE_TEXTURE, "hint_white", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_BLACK_TEXTURE, "hint_black", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ANISOTROPY_TEXTURE, "hint_anisotropy", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_R, "hint_roughness_r", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_G, "hint_roughness_g", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_B, "hint_roughness_b", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_A, "hint_roughness_a", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_NEAREST, "filter_nearest", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_LINEAR, "filter_linear", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC, "filter_nearest_mipmap_anisotropic", CF_UNSPECIFIED, {}, {} },
+ { TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC, "filter_linear_mipmap_anisotropic", CF_UNSPECIFIED, {}, {} },
+ { TK_REPEAT_ENABLE, "repeat_enable", CF_UNSPECIFIED, {}, {} },
+ { TK_REPEAT_DISABLE, "repeat_disable", CF_UNSPECIFIED, {}, {} },
+
+ { TK_ERROR, nullptr, CF_UNSPECIFIED, {}, {} }
};
ShaderLanguage::Token ShaderLanguage::_get_token() {
@@ -543,7 +581,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
default: {
char_idx--; //go back one, since we have no idea what this is
- if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
+ if (is_digit(GETCHAR(0)) || (GETCHAR(0) == '.' && is_digit(GETCHAR(1)))) {
// parse number
bool hexa_found = false;
bool period_found = false;
@@ -584,7 +622,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
const char32_t symbol = String::char_lowercase(GETCHAR(i));
bool error = false;
- if (_is_number(symbol)) {
+ if (is_digit(symbol)) {
if (end_suffix_found) {
error = true;
}
@@ -617,8 +655,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
break;
}
}
- } else if (!hexa_found || !_is_hex(symbol)) {
- if (_is_text_char(symbol)) {
+ } else if (!hexa_found || !is_hex_digit(symbol)) {
+ if (is_ascii_identifier_char(symbol)) {
error = true;
} else {
break;
@@ -644,12 +682,12 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
char32_t last_char = str[str.length() - 1];
- if (hexa_found) { // Integer(hex)
+ if (hexa_found) { // Integer (hex).
if (str.size() > 11 || !str.is_valid_hex_number(true)) { // > 0xFFFFFFFF
return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
}
} else if (period_found || exponent_found || float_suffix_found) { // Float
- if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
+ if (exponent_found && (!is_digit(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
}
if (period_found) {
@@ -660,7 +698,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
}
} else {
//checks for eg. "1." or "1.99" notations
- if (last_char != '.' && !_is_number(last_char)) {
+ if (last_char != '.' && !is_digit(last_char)) {
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
}
}
@@ -690,7 +728,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
}
if (!str.is_valid_int()) {
if (uint_suffix_found) {
- return _make_token(TK_ERROR, "Invalid (usigned integer) numeric constant");
+ return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant");
} else {
return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
}
@@ -723,11 +761,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_PERIOD);
}
- if (_is_text_char(GETCHAR(0))) {
+ if (is_ascii_identifier_char(GETCHAR(0))) {
// parse identifier
String str;
- while (_is_text_char(GETCHAR(0))) {
+ while (is_ascii_identifier_char(GETCHAR(0))) {
str += char32_t(GETCHAR(0));
char_idx++;
}
@@ -763,6 +801,19 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
#undef GETCHAR
}
+bool ShaderLanguage::_lookup_next(Token &r_tk) {
+ TkPos pre_pos = _get_tkpos();
+ int line = pre_pos.tk_line;
+ _get_token();
+ Token tk = _get_token();
+ _set_tkpos(pre_pos);
+ if (tk.line == line) {
+ r_tk = tk;
+ return true;
+ }
+ return false;
+}
+
String ShaderLanguage::token_debug(const String &p_code) {
clear();
@@ -863,6 +914,13 @@ bool ShaderLanguage::is_token_precision(TokenType p_type) {
p_type == TK_PRECISION_HIGH);
}
+bool ShaderLanguage::is_token_arg_qual(TokenType p_type) {
+ return (
+ p_type == TK_ARG_IN ||
+ p_type == TK_ARG_OUT ||
+ p_type == TK_ARG_INOUT);
+}
+
ShaderLanguage::DataPrecision ShaderLanguage::get_token_precision(TokenType p_type) {
if (p_type == TK_PRECISION_LOW) {
return PRECISION_LOWP;
@@ -977,9 +1035,8 @@ void ShaderLanguage::clear() {
completion_base = TYPE_VOID;
completion_base_array = false;
- unknown_varying_usages.clear();
-
#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_GLOBAL_SPACE;
used_constants.clear();
used_varyings.clear();
used_uniforms.clear();
@@ -2744,13 +2801,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
//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()));
+ _set_error(vformat(RTR("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))));
+ _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type)));
return false;
}
}
@@ -2826,7 +2883,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
bool error = false;
if (p_func->arguments[arg]->type == Node::TYPE_VARIABLE) {
- const VariableNode *vn = (VariableNode *)p_func->arguments[arg];
+ const VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg]);
bool is_const = false;
ConstantNode::Value value;
@@ -2838,7 +2895,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
} else {
if (p_func->arguments[arg]->type == Node::TYPE_CONSTANT) {
- ConstantNode *cn = (ConstantNode *)p_func->arguments[arg];
+ const ConstantNode *cn = static_cast<ConstantNode *>(p_func->arguments[arg]);
if (cn->get_datatype() == TYPE_INT && cn->values.size() == 1) {
int value = cn->values[0].sint;
@@ -2854,7 +2911,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
}
if (error) {
- _set_error(vformat("Expected integer constant within %s..%s range.", min, max));
+ _set_error(vformat(RTR("Expected integer constant within [%d..%d] range."), min, max));
return false;
}
}
@@ -2873,7 +2930,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
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.");
+ _set_error(vformat(RTR("Argument %d of function '%s' is not a variable, array, or member."), arg_idx + 1, String(name)));
return false;
}
@@ -2897,7 +2954,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
fail = true;
} else {
if (shader->varyings.has(varname)) {
- _set_error(vformat("Varyings cannot be passed for '%s' parameter!", "out"));
+ _set_error(vformat(RTR("Varyings cannot be passed for the '%s' parameter."), "out"));
return false;
}
if (p_function_info.built_ins.has(varname)) {
@@ -2910,7 +2967,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
}
if (fail) {
- _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out"));
+ _set_error(vformat(RTR("A constant value cannot be passed for the '%s' parameter."), "out"));
return false;
}
@@ -2923,7 +2980,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
n = static_cast<const MemberNode *>(n)->owner;
}
if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
+ _set_error(vformat(RTR("Argument %d of function '%s' is not a variable, array, or member."), arg_idx + 1, String(name)));
return false;
}
if (n->type == Node::TYPE_VARIABLE) {
@@ -2953,7 +3010,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
if (!valid) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member.");
+ _set_error(vformat(RTR("Argument %d of function '%s' can only take a local variable, array, or member."), arg_idx + 1, String(name)));
return false;
}
}
@@ -3000,16 +3057,15 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
arglist += get_datatype_name(builtin_func_defs[builtin_idx].args[i]);
}
- String err = "Built-in function \"" + String(name) + "(" + arglist + ")\" is supported only on high-end platform!";
- _set_error(err);
+ _set_error(vformat(RTR("Built-in function \"%s(%s)\" is only supported on high-end platforms."), String(name), arglist));
return false;
}
if (failed_builtin) {
- String err = "Invalid arguments for built-in function: " + String(name) + "(";
+ String arg_list;
for (int i = 0; i < argcount; i++) {
if (i > 0) {
- err += ",";
+ arg_list += ",";
}
String arg_name;
@@ -3023,10 +3079,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
arg_name += itos(args3[i]);
arg_name += "]";
}
- err += arg_name;
+ arg_list += arg_name;
}
- err += ")";
- _set_error(err);
+ _set_error(vformat(RTR("Invalid arguments for the built-in function: \"%s(%s)\"."), String(name), arg_list));
return false;
}
@@ -3043,7 +3098,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
if (name == exclude_function) {
- _set_error("Recursion is not allowed");
+ _set_error(RTR("Recursion is not allowed."));
return false;
}
@@ -3056,7 +3111,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
if (!shader->functions[i].callable) {
- _set_error("Function '" + String(name) + " can't be called from source code.");
+ _set_error(vformat(RTR("Function '%s' can't be called from source code."), String(name)));
return false;
}
@@ -3115,7 +3170,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
arg_name += "]";
}
- _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));
+ _set_error(vformat(RTR("Invalid argument for \"%s(%s)\" function: argument %d should be %s but is %s."), String(name), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
}
@@ -3152,9 +3207,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
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()));
+ _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), 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()));
+ _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
}
return false;
@@ -3192,7 +3247,7 @@ bool ShaderLanguage::_compare_datatypes(DataType p_datatype_a, String p_datatype
type_name2 += "]";
}
- _set_error("Invalid assignment of '" + type_name2 + "' to '" + type_name + "'");
+ _set_error(vformat(RTR("Invalid assignment of '%s' to '%s'."), type_name2, type_name));
}
return result;
}
@@ -3237,7 +3292,7 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Functio
return true;
} else if (tk.type != TK_COMMA) {
// something is broken
- _set_error("Expected ',' or ')' after argument");
+ _set_error(RTR("Expected ',' or ')' after argument."));
return false;
}
}
@@ -3482,7 +3537,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
- value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ value = Variant(Quaternion(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
}
break;
case ShaderLanguage::TYPE_UINT:
@@ -3532,7 +3587,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
}
value = Variant(array);
} else {
- value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ value = Variant(Quaternion(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
}
break;
case ShaderLanguage::TYPE_FLOAT:
@@ -3563,13 +3618,25 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
if (array_size > 0) {
array_size *= 3;
- PackedVector3Array array = PackedVector3Array();
- for (int i = 0; i < array_size; i += 3) {
- array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real));
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ PackedColorArray array = PackedColorArray();
+ for (int i = 0; i < array_size; i += 3) {
+ array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real));
+ }
+ value = Variant(array);
+ } else {
+ PackedVector3Array array = PackedVector3Array();
+ for (int i = 0; i < array_size; i += 3) {
+ array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real));
+ }
+ value = Variant(array);
}
- value = Variant(array);
} else {
- value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real));
+ } else {
+ value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ }
}
break;
case ShaderLanguage::TYPE_VEC4:
@@ -3596,7 +3663,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
} else {
- value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ value = Variant(Quaternion(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
}
}
break;
@@ -3775,9 +3842,19 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
break;
case ShaderLanguage::TYPE_VEC3:
if (p_uniform.array_size > 0) {
- pi.type = Variant::PACKED_VECTOR3_ARRAY;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.hint = PROPERTY_HINT_COLOR_NO_ALPHA;
+ pi.type = Variant::PACKED_COLOR_ARRAY;
+ } else {
+ pi.type = Variant::PACKED_VECTOR3_ARRAY;
+ }
} else {
- pi.type = Variant::VECTOR3;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.hint = PROPERTY_HINT_COLOR_NO_ALPHA;
+ pi.type = Variant::COLOR;
+ } else {
+ pi.type = Variant::VECTOR3;
+ }
}
break;
case ShaderLanguage::TYPE_VEC4: {
@@ -3791,7 +3868,7 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
pi.type = Variant::COLOR;
} else {
- pi.type = Variant::PLANE;
+ pi.type = Variant::QUATERNION;
}
}
} break;
@@ -3868,55 +3945,77 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
return pi;
}
-uint32_t ShaderLanguage::get_type_size(DataType p_type) {
+uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) {
switch (p_type) {
case TYPE_VOID:
return 0;
case TYPE_BOOL:
- case TYPE_INT:
- case TYPE_UINT:
- case TYPE_FLOAT:
return 4;
case TYPE_BVEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_VEC2:
return 8;
case TYPE_BVEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_VEC3:
return 12;
case TYPE_BVEC4:
+ return 16;
+ case TYPE_INT:
+ return 4;
+ case TYPE_IVEC2:
+ return 8;
+ case TYPE_IVEC3:
+ return 12;
case TYPE_IVEC4:
+ return 16;
+ case TYPE_UINT:
+ return 4;
+ case TYPE_UVEC2:
+ return 8;
+ case TYPE_UVEC3:
+ return 12;
case TYPE_UVEC4:
+ return 16;
+ case TYPE_FLOAT:
+ return 4;
+ case TYPE_VEC2:
+ return 8;
+ case TYPE_VEC3:
+ return 12;
case TYPE_VEC4:
return 16;
case TYPE_MAT2:
- return 8;
+ return 32; // 4 * 4 + 4 * 4
case TYPE_MAT3:
- return 12;
+ return 48; // 4 * 4 + 4 * 4 + 4 * 4
case TYPE_MAT4:
- return 16;
+ return 64;
case TYPE_SAMPLER2D:
+ return 16;
case TYPE_ISAMPLER2D:
+ return 16;
case TYPE_USAMPLER2D:
+ return 16;
case TYPE_SAMPLER2DARRAY:
+ return 16;
case TYPE_ISAMPLER2DARRAY:
+ return 16;
case TYPE_USAMPLER2DARRAY:
+ return 16;
case TYPE_SAMPLER3D:
+ return 16;
case TYPE_ISAMPLER3D:
+ return 16;
case TYPE_USAMPLER3D:
+ return 16;
case TYPE_SAMPLERCUBE:
+ return 16;
case TYPE_SAMPLERCUBEARRAY:
- return 4; //not really, but useful for indices
+ return 16;
case TYPE_STRUCT:
- // FIXME: Implement.
- return 0;
- case ShaderLanguage::TYPE_MAX:
return 0;
+ case TYPE_MAX: {
+ ERR_FAIL_V(0);
+ };
}
- return 0;
+ ERR_FAIL_V(0);
}
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
@@ -4122,47 +4221,10 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St
return true;
}
-bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) {
- switch (p_varying.stage) {
- case ShaderNode::Varying::STAGE_UNKNOWN:
- VaryingUsage usage;
- usage.var = &p_varying;
- usage.line = tk_line;
- unknown_varying_usages.push_back(usage);
- break;
- case ShaderNode::Varying::STAGE_VERTEX:
- if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) {
- p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT;
- }
- break;
- case ShaderNode::Varying::STAGE_FRAGMENT:
- if (current_function == varying_function_names.light) {
- p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT;
- }
- break;
- default:
- break;
- }
- return true;
-}
-
-bool ShaderLanguage::_check_varying_usages(int *r_error_line, String *r_error_message) const {
- for (const List<ShaderLanguage::VaryingUsage>::Element *E = unknown_varying_usages.front(); E; E = E->next()) {
- ShaderNode::Varying::Stage stage = E->get().var->stage;
- if (stage != ShaderNode::Varying::STAGE_UNKNOWN && stage != ShaderNode::Varying::STAGE_VERTEX && stage != ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT) {
- *r_error_line = E->get().line;
- *r_error_message = RTR("Fragment-stage varying could not been accessed in custom function!");
- return false;
- }
- }
-
- return true;
-}
-
bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
switch (p_node->type) {
case Node::TYPE_OPERATOR: {
- OperatorNode *op_node = (OperatorNode *)p_node;
+ const OperatorNode *op_node = static_cast<const OperatorNode *>(p_node);
for (int i = int(op_node->op == OP_CALL); i < op_node->arguments.size(); i++) {
if (!_check_node_constness(op_node->arguments[i])) {
return false;
@@ -4172,13 +4234,13 @@ bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
case Node::TYPE_CONSTANT:
break;
case Node::TYPE_VARIABLE: {
- VariableNode *varn = (VariableNode *)p_node;
+ const VariableNode *varn = static_cast<const VariableNode *>(p_node);
if (!varn->is_const) {
return false;
}
} break;
case Node::TYPE_ARRAY: {
- ArrayNode *arrn = (ArrayNode *)p_node;
+ const ArrayNode *arrn = static_cast<const ArrayNode *>(p_node);
if (!arrn->is_const) {
return false;
}
@@ -4264,14 +4326,14 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam
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) {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name)));
return false;
} else if (arg->tex_argument_check) {
//was checked, verify that filter and repeat are the same
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.");
+ _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter or repeat setting."), p_argument, String(p_name)));
return false;
}
} else {
@@ -4298,14 +4360,14 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
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) {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name)));
return false;
} else if (arg->tex_builtin_check) {
//was checked, verify that the built-in is the same
if (arg->tex_builtin == p_builtin) {
return true;
} else {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported.");
+ _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using different built-ins. Only calling with the same built-in is supported."), p_argument, String(p_name)));
return false;
}
} else {
@@ -4326,114 +4388,87 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
-ShaderLanguage::Node *ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size) {
- int array_size = 0;
-
- 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;
- bool is_const = false;
-
- _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) {
- array_size = value;
- }
- } else if (data_type == TYPE_UINT) {
- uint32_t value = v.uint;
- if (value > 0U) {
- array_size = value;
- }
- }
- }
- }
- } else if (n->type == Node::TYPE_OPERATOR) {
- _set_error("Array size expressions are not yet implemented.");
- return nullptr;
- }
+Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_forbid_unknown_size, Node **r_size_expression, int *r_array_size, bool *r_unknown_size) {
+ bool error = false;
+ if (r_array_size != nullptr && *r_array_size > 0) {
+ error = true;
}
-
- r_array_size = array_size;
- return n;
-}
-
-Error ShaderLanguage::_parse_global_array_size(int &r_array_size, const FunctionInfo &p_function_info) {
- if (r_array_size > 0) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
- }
- TkPos pos = _get_tkpos();
- Token tk = _get_token();
-
- int array_size = 0;
-
- if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
- _set_tkpos(pos);
- Node *n = _parse_array_size(nullptr, p_function_info, array_size);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
- } else if (((int)tk.constant) > 0) {
- array_size = (uint32_t)tk.constant;
- }
-
- if (array_size <= 0) {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
+ if (r_unknown_size != nullptr && *r_unknown_size) {
+ error = true;
}
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
+ if (error) {
+ _set_error(vformat(RTR("Array size is already defined.")));
return ERR_PARSE_ERROR;
}
- r_array_size = array_size;
- return OK;
-}
-
-Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, Node *&r_size_expression, int &r_array_size, bool &r_is_unknown_size) {
TkPos pos = _get_tkpos();
Token tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
- r_is_unknown_size = true;
+ if (p_forbid_unknown_size) {
+ _set_error(vformat(RTR("Unknown array size is forbidden in that context.")));
+ return ERR_PARSE_ERROR;
+ }
+ if (r_unknown_size != nullptr) {
+ *r_unknown_size = true;
+ }
} else {
- int size = 0;
+ int array_size = 0;
+
if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
_set_tkpos(pos);
- int array_size = 0;
- Node *n = _parse_array_size(p_block, p_function_info, array_size);
- if (!n) {
- return ERR_PARSE_ERROR;
+ 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;
+ bool is_const = false;
+
+ _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) {
+ array_size = value;
+ }
+ } else if (data_type == TYPE_UINT) {
+ uint32_t value = v.uint;
+ if (value > 0U) {
+ array_size = value;
+ }
+ }
+ }
+ }
+ } else if (n->type == Node::TYPE_OPERATOR) {
+ _set_error(vformat(RTR("Array size expressions are not supported.")));
+ return ERR_PARSE_ERROR;
+ }
+ if (r_size_expression != nullptr) {
+ *r_size_expression = n;
+ }
}
- size = array_size;
- r_size_expression = n;
} else if (((int)tk.constant) > 0) {
- size = (uint32_t)tk.constant;
+ array_size = (uint32_t)tk.constant;
}
- if (size <= 0) {
- _set_error("Expected single integer constant > 0");
+ if (array_size <= 0) {
+ _set_error(RTR("Expected a positive integer constant."));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
+ _set_expected_error("]");
return ERR_PARSE_ERROR;
}
- r_array_size = size;
+ if (r_array_size != nullptr) {
+ *r_array_size = array_size;
+ }
}
-
return OK;
}
@@ -4453,49 +4488,20 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
struct_name = tk.text;
} else {
if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
+ _set_error(RTR("Invalid data type for the 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) {
- undefined_size = true;
- 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();
- }
+ Error error = _parse_array_size(p_block, p_function_info, false, nullptr, &array_size, &undefined_size);
+ if (error != OK) {
+ return nullptr;
}
+ tk = _get_token();
} else {
- _set_error("Expected '['");
+ _set_expected_error("[");
return nullptr;
}
}
@@ -4533,20 +4539,20 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
break;
} else {
if (auto_size) {
- _set_error("Expected '}' or ','");
+ _set_expected_error("}", ",");
} else {
- _set_error("Expected ')' or ','");
+ _set_expected_error(")", ",");
}
return nullptr;
}
idx++;
}
if (!auto_size && !undefined_size && an->initializer.size() != array_size) {
- _set_error("Array size mismatch");
+ _set_error(RTR("Array size mismatch."));
return nullptr;
}
} else {
- _set_error("Expected array initialization!");
+ _set_error(RTR("Expected array initialization."));
return nullptr;
}
@@ -4576,7 +4582,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
- _set_error("Invalid data type for array");
+ _set_error(RTR("Invalid data type for the array."));
return nullptr;
}
@@ -4589,65 +4595,42 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
}
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- TkPos pos = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
+ bool is_unknown_size = false;
+ Error error = _parse_array_size(p_block, p_function_info, false, nullptr, &array_size, &is_unknown_size);
+ if (error != OK) {
+ return nullptr;
+ }
+ if (is_unknown_size) {
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();
- }
}
+ tk = _get_token();
} else {
- _set_error("Expected '['");
+ _set_expected_error("[");
return nullptr;
}
if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) {
- String error_str = "Cannot convert from '";
+ String from;
if (type == TYPE_STRUCT) {
- error_str += struct_name;
+ from += struct_name;
} else {
- error_str += get_datatype_name(type);
+ from += get_datatype_name(type);
}
- error_str += "[";
- error_str += itos(array_size);
- error_str += "]'";
- error_str += " to '";
+ from += "[";
+ from += itos(array_size);
+ from += "]'";
+
+ String to;
if (type == TYPE_STRUCT) {
- error_str += p_struct_name;
+ to += p_struct_name;
} else {
- error_str += get_datatype_name(p_type);
+ to += get_datatype_name(p_type);
}
- error_str += "[";
- error_str += itos(p_array_size);
- error_str += "]'";
- _set_error(error_str);
+ to += "[";
+ to += itos(p_array_size);
+ to += "]'";
+
+ _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to));
return nullptr;
}
}
@@ -4678,19 +4661,19 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
break;
} else {
if (auto_size) {
- _set_error("Expected '}' or ','");
+ _set_expected_error("}", ",");
} else {
- _set_error("Expected ')' or ','");
+ _set_expected_error(")", ",");
}
return nullptr;
}
}
if (an->initializer.size() != p_array_size) {
- _set_error("Array size mismatch");
+ _set_error(RTR("Array size mismatch."));
return nullptr;
}
} else {
- _set_error("Expected array initialization!");
+ _set_error(RTR("Expected array initialization."));
return nullptr;
}
@@ -4721,7 +4704,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' in expression");
+ _set_error(RTR("Expected ')' in expression."));
return nullptr;
}
@@ -4769,7 +4752,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_TYPE_VOID) {
//make sure void is not used in expression
- _set_error("Void value not allowed in Expression");
+ _set_error(RTR("Void value not allowed in expression."));
return nullptr;
} else if (is_token_nonvoid_datatype(tk.type) || tk.type == TK_CURLY_BRACKET_OPEN) {
if (tk.type == TK_CURLY_BRACKET_OPEN) {
@@ -4779,16 +4762,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = _parse_array_constructor(p_block, p_function_info);
} else {
DataType datatype;
- DataPrecision precision;
- bool precision_defined = false;
+ DataPrecision precision = PRECISION_DEFAULT;
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- precision_defined = true;
tk = _get_token();
}
datatype = get_token_datatype(tk.type);
+ if (precision != PRECISION_DEFAULT && _validate_precision(datatype, precision) != OK) {
+ return nullptr;
+ }
+
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
@@ -4798,7 +4783,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = _parse_array_constructor(p_block, p_function_info);
} else {
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after type name");
+ _set_error(RTR("Expected '(' after the type name."));
return nullptr;
}
//basic type constructor
@@ -4806,7 +4791,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_CONSTRUCT;
- if (precision_defined) {
+ if (precision != PRECISION_DEFAULT) {
func->return_precision_cache = precision;
}
@@ -4831,7 +4816,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
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) + "'");
+ _set_error(vformat(RTR("No matching constructor found for: '%s'."), String(funcname->name)));
return nullptr;
}
@@ -4888,7 +4873,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (i + 1 < pstruct->members.size()) {
tk = _get_token();
if (tk.type != TK_COMMA) {
- _set_error("Expected ','");
+ _set_expected_error(",");
return nullptr;
}
}
@@ -4896,7 +4881,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')'");
+ _set_expected_error(")");
return nullptr;
}
@@ -4920,7 +4905,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ShaderLanguage::BlockNode *bnode = p_block;
while (bnode) {
if (bnode->variables.has(name)) {
- _set_error("Expected function name");
+ _set_error(RTR("Expected a function name."));
return nullptr;
}
bnode = bnode->parent_block;
@@ -4957,7 +4942,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
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) + "'");
+ _set_error(vformat(RTR("No matching function found for: '%s'."), String(funcname->name)));
return nullptr;
}
completion_class = TAG_GLOBAL; // reset sub-class
@@ -4991,55 +4976,104 @@ 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].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) {
- if (!call_function->arguments[i].is_const) {
+ bool error = false;
+ Node *n = func->arguments[argidx];
+ ArgumentQualifier arg_qual = call_function->arguments[i].qualifier;
+ bool is_out_arg = arg_qual != ArgumentQualifier::ARGUMENT_QUALIFIER_IN;
+
+ if (n->type == Node::TYPE_VARIABLE || n->type == Node::TYPE_ARRAY) {
+ StringName varname;
+
+ if (n->type == Node::TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ varname = vn->name;
+ } else { // TYPE_ARRAY
+ ArrayNode *an = static_cast<ArrayNode *>(n);
+ varname = an->name;
+ }
+
+ if (shader->varyings.has(varname)) {
+ switch (shader->varyings[varname].stage) {
+ case ShaderNode::Varying::STAGE_UNKNOWN: {
+ _set_error(vformat(RTR("Varying '%s' must be assigned in the vertex or fragment function first."), varname));
+ return nullptr;
+ }
+ case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT:
+ [[fallthrough]];
+ case ShaderNode::Varying::STAGE_VERTEX:
+ if (is_out_arg && current_function != varying_function_names.vertex) { // inout/out
+ error = true;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT:
+ [[fallthrough]];
+ case ShaderNode::Varying::STAGE_FRAGMENT:
+ if (!is_out_arg) {
+ if (current_function != varying_function_names.fragment && current_function != varying_function_names.light) {
+ error = true;
+ }
+ } else if (current_function != varying_function_names.fragment) { // inout/out
+ error = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (error) {
+ _set_error(vformat(RTR("Varying '%s' cannot be passed for the '%s' parameter in that context."), varname, _get_qualifier_str(arg_qual)));
+ return nullptr;
+ }
+ }
+ }
+
+ bool is_const_arg = call_function->arguments[i].is_const;
+
+ if (is_const_arg || is_out_arg) {
+ StringName varname;
+
+ if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR || n->type == Node::TYPE_ARRAY_CONSTRUCT) {
+ if (!is_const_arg) {
error = true;
}
} else if (n->type == Node::TYPE_ARRAY) {
ArrayNode *an = static_cast<ArrayNode *>(n);
- if (an->call_expression != nullptr || an->is_const) {
+ if (!is_const_arg && (an->call_expression != nullptr || an->is_const)) {
error = true;
}
+ varname = an->name;
} else if (n->type == Node::TYPE_VARIABLE) {
VariableNode *vn = static_cast<VariableNode *>(n);
- if (vn->is_const) {
+ if (vn->is_const && !is_const_arg) {
error = true;
- } else {
- StringName varname = vn->name;
- if (shader->constants.has(varname)) {
- error = true;
- } else if (shader->uniforms.has(varname)) {
- error = true;
- } else {
- if (shader->varyings.has(varname)) {
- _set_error(vformat("Varyings cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier)));
- return nullptr;
- }
- if (p_function_info.built_ins.has(varname)) {
- BuiltInInfo info = p_function_info.built_ins[varname];
- if (info.constant) {
- error = true;
- }
- }
- }
}
+ varname = vn->name;
} else if (n->type == Node::TYPE_MEMBER) {
MemberNode *mn = static_cast<MemberNode *>(n);
- if (mn->basetype_const) {
+ if (mn->basetype_const && is_out_arg) {
error = true;
}
}
+ if (!error && varname != StringName()) {
+ if (shader->constants.has(varname)) {
+ error = true;
+ } else if (shader->uniforms.has(varname)) {
+ error = true;
+ } else if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
+ if (info.constant) {
+ error = true;
+ }
+ }
+ }
+
if (error) {
- _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier)));
+ _set_error(vformat(RTR("A constant value cannot be passed for '%s' parameter."), _get_qualifier_str(arg_qual)));
return nullptr;
}
}
if (is_sampler_type(call_function->arguments[i].type)) {
//let's see where our argument comes from
- Node *n = func->arguments[argidx];
ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
VariableNode *vn = static_cast<VariableNode *>(n);
StringName varname = vn->name;
@@ -5116,12 +5150,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
idx++;
}
if (!found) {
- _set_error("Unknown identifier in expression: " + String(identifier));
+ _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier)));
return nullptr;
}
} else {
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));
+ _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier)));
return nullptr;
}
if (ident_type == IDENTIFIER_VARYING) {
@@ -5143,15 +5177,27 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
} else {
- if (!_validate_varying_using(shader->varyings[identifier], &error)) {
- _set_error(error);
- return nullptr;
+ ShaderNode::Varying &var = shader->varyings[identifier];
+
+ switch (var.stage) {
+ case ShaderNode::Varying::STAGE_VERTEX:
+ if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) {
+ var.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_FRAGMENT:
+ if (current_function == varying_function_names.light) {
+ var.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT;
+ }
+ break;
+ default:
+ break;
}
}
}
if (ident_type == IDENTIFIER_FUNCTION) {
- _set_error("Can't use function as identifier: " + String(identifier));
+ _set_error(vformat(RTR("Can't use function as identifier: '%s'."), String(identifier)));
return nullptr;
}
if (is_const) {
@@ -5173,7 +5219,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_OP_ASSIGN) {
if (is_const) {
- _set_error("Constants cannot be modified.");
+ _set_error(RTR("Constants cannot be modified."));
return nullptr;
}
assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size);
@@ -5182,13 +5228,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
} else if (tk.type == TK_PERIOD) {
completion_class = TAG_ARRAY;
- p_block->block_tag = SubClassTag::TAG_ARRAY;
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ }
call_expression = _parse_and_reduce_expression(p_block, p_function_info);
- p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ }
if (!call_expression) {
return nullptr;
}
- data_type = call_expression->get_datatype();
} else if (tk.type == TK_BRACKET_OPEN) { // indexing
index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
@@ -5196,17 +5245,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) {
- _set_error("Only integer expressions are allowed for indexing.");
+ _set_error(RTR("Only integer expressions are allowed for indexing."));
return nullptr;
}
if (index_expression->type == Node::TYPE_CONSTANT) {
- ConstantNode *cnode = (ConstantNode *)index_expression;
+ ConstantNode *cnode = static_cast<ConstantNode *>(index_expression);
if (cnode) {
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));
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), value, 0, array_size - 1));
return nullptr;
}
}
@@ -5215,7 +5264,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
+ _set_expected_error("]");
return nullptr;
}
} else {
@@ -5245,9 +5294,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
#ifdef DEBUG_ENABLED
if (check_warnings) {
StringName func_name;
+ BlockNode *b = p_block;
- if (p_block && p_block->parent_function) {
- func_name = p_block->parent_function->name;
+ while (b) {
+ if (b->parent_function) {
+ func_name = b->parent_function->name;
+ break;
+ } else {
+ b = b->parent_block;
+ }
}
_parse_used_identifier(identifier, ident_type, func_name);
@@ -5283,21 +5338,34 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.push_back(e);
continue;
} else {
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected expression, found: " + get_token_text(tk));
- return nullptr;
- } else {
-#if DEBUG_ENABLED
- if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
- _add_line_warning(ShaderWarning::FORMATTING_ERROR, "Empty statement. Remove ';' to fix this warning.");
- }
-#endif // DEBUG_ENABLED
+ bool valid = false;
+ if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION && tk.type == TK_PARENTHESIS_CLOSE) {
+ valid = true;
_set_tkpos(prepos);
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_EMPTY;
expr = func;
}
+ if (!valid) {
+ if (tk.type != TK_SEMICOLON) {
+ _set_error(vformat(RTR("Expected expression, found: '%s'."), get_token_text(tk)));
+ return nullptr;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_FOR_INIT && p_block->block_type != BlockNode::BLOCK_TYPE_FOR_CONDITION)) {
+ if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
+ _add_line_warning(ShaderWarning::FORMATTING_ERROR, RTR("Empty statement. Remove ';' to fix this warning."));
+ }
+ }
+#endif // DEBUG_ENABLED
+ _set_tkpos(prepos);
+
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_EMPTY;
+ expr = func;
+ }
+ }
}
ERR_FAIL_COND_V(!expr, nullptr);
@@ -5316,9 +5384,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (!expr->is_indexed() && expr->get_array_size() > 0) {
completion_class = TAG_ARRAY;
- p_block->block_tag = SubClassTag::TAG_ARRAY;
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ }
Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
- p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ }
if (!call_expression) {
return nullptr;
}
@@ -5336,7 +5408,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (identifier == StringName()) {
- _set_error("Expected identifier as member");
+ _set_error(RTR("Expected an identifier as a member."));
return nullptr;
}
String ident = identifier;
@@ -5581,12 +5653,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (mix_error) {
- _set_error("Cannot combine symbols from different sets in expression ." + ident);
+ _set_error(vformat(RTR("Cannot combine symbols from different sets in expression '.%s'."), ident));
return nullptr;
}
if (!ok) {
- _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
+ _set_error(vformat(RTR("Invalid member for '%s' expression: '.%s'."), (dt == TYPE_STRUCT ? st : get_datatype_name(dt)), ident));
return nullptr;
}
@@ -5606,7 +5678,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
tk = _get_token();
if (tk.type == TK_OP_ASSIGN) {
if (last_type == IDENTIFIER_CONSTANT) {
- _set_error("Constants cannot be modified.");
+ _set_error(RTR("Constants cannot be modified."));
return nullptr;
}
Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size);
@@ -5616,14 +5688,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->assign_expression = assign_expression;
} else if (tk.type == TK_PERIOD) {
completion_class = TAG_ARRAY;
- p_block->block_tag = SubClassTag::TAG_ARRAY;
- Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
- p_block->block_tag = SubClassTag::TAG_GLOBAL;
- if (!call_expression) {
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ }
+ mn->call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ if (p_block != nullptr) {
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ }
+ if (!mn->call_expression) {
return nullptr;
}
- mn->datatype = call_expression->get_datatype();
- mn->call_expression = call_expression;
} else if (tk.type == TK_BRACKET_OPEN) {
Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
@@ -5631,17 +5705,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) {
- _set_error("Only integer expressions are allowed for indexing.");
+ _set_error(RTR("Only integer expressions are allowed for indexing."));
return nullptr;
}
if (index_expression->type == Node::TYPE_CONSTANT) {
- ConstantNode *cnode = (ConstantNode *)index_expression;
+ ConstantNode *cnode = static_cast<ConstantNode *>(index_expression);
if (cnode) {
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));
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), value, 0, array_size - 1));
return nullptr;
}
}
@@ -5650,7 +5724,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
+ _set_expected_error("]");
return nullptr;
}
mn->index_expression = index_expression;
@@ -5677,7 +5751,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (index->get_array_size() != 0 || (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT)) {
- _set_error("Only integer expressions are allowed for indexing.");
+ _set_error(RTR("Only integer expressions are allowed for indexing."));
return nullptr;
}
@@ -5688,7 +5762,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (index->type == Node::TYPE_CONSTANT) {
uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
if (index_constant >= (uint32_t)expr->get_array_size()) {
- _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1));
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, expr->get_array_size() - 1));
return nullptr;
}
}
@@ -5706,7 +5780,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (index->type == Node::TYPE_CONSTANT) {
uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
if (index_constant >= 2) {
- _set_error("Index out of range (0-1)");
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 1));
return nullptr;
}
}
@@ -5740,7 +5814,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (index->type == Node::TYPE_CONSTANT) {
uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
if (index_constant >= 3) {
- _set_error("Index out of range (0-2)");
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 2));
return nullptr;
}
}
@@ -5773,7 +5847,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (index->type == Node::TYPE_CONSTANT) {
uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
if (index_constant >= 4) {
- _set_error("Index out of range (0-3)");
+ _set_error(vformat(RTR("Index [%d] out of range [%d..%d]."), index_constant, 0, 3));
return nullptr;
}
}
@@ -5799,7 +5873,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
break;
default: {
- _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
+ _set_error(vformat(RTR("An object of type '%s' can't be indexed."), (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype()))));
return nullptr;
}
}
@@ -5814,7 +5888,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']' after indexing expression");
+ _set_expected_error("]");
return nullptr;
}
@@ -5824,12 +5898,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->arguments.push_back(expr);
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
- _set_error("Invalid base type for increment/decrement operator");
+ _set_error(RTR("Invalid base type for increment/decrement operator."));
return nullptr;
}
if (!_validate_assign(expr, p_function_info)) {
- _set_error("Invalid use of increment/decrement operator in constant expression.");
+ _set_error(RTR("Invalid use of increment/decrement operator in a constant expression."));
return nullptr;
}
expr = op;
@@ -5946,7 +6020,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
o.op = OP_SELECT_ELSE;
break;
default: {
- _set_error("Invalid token for operator: " + get_token_text(tk));
+ _set_error(vformat(RTR("Invalid token for the operator: '%s'."), get_token_text(tk)));
return nullptr;
}
}
@@ -6098,7 +6172,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_V(nullptr); //unexpected operator
}
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) &&
(!expression[i - 1].is_op && !expression[i + 1].is_op) &&
(expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) {
@@ -6125,7 +6199,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr_pos++;
if (expr_pos == expression.size()) {
//can happen..
- _set_error("Unexpected end of expression...");
+ _set_error(RTR("Unexpected end of expression."));
return nullptr;
}
}
@@ -6135,7 +6209,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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_function_info)) {
- _set_error("Can't use increment/decrement operator in constant expression.");
+ _set_error(RTR("Can't use increment/decrement operator in a constant expression."));
return nullptr;
}
op->arguments.push_back(expression[i + 1].node);
@@ -6147,7 +6221,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
String at;
for (int j = 0; j < op->arguments.size(); j++) {
if (j > 0) {
- at += " and ";
+ at += ", ";
}
at += get_datatype_name(op->arguments[j]->get_datatype());
if (!op->arguments[j]->is_indexed() && op->arguments[j]->get_array_size() > 0) {
@@ -6156,7 +6230,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
at += "]";
}
}
- _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
+ _set_error(vformat(RTR("Invalid arguments to unary operator '%s': %s."), get_operator_text(op->op), at));
return nullptr;
}
expression.remove_at(i + 1);
@@ -6164,12 +6238,12 @@ 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...");
+ _set_parsing_error();
ERR_FAIL_V(nullptr);
}
if (next_op + 2 >= expression.size() || !expression[next_op + 2].is_op || expression[next_op + 2].op != OP_SELECT_ELSE) {
- _set_error("Missing matching ':' for select operator");
+ _set_error(RTR("Missing matching ':' for select operator."));
return nullptr;
}
@@ -6185,7 +6259,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
- at += " and ";
+ at += ", ";
}
at += get_datatype_name(op->arguments[i]->get_datatype());
if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) {
@@ -6194,7 +6268,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
at += "]";
}
}
- _set_error("Invalid argument to ternary ?: operator: " + at);
+ _set_error(vformat(RTR("Invalid argument to ternary operator: '%s'."), at));
return nullptr;
}
@@ -6204,7 +6278,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
if (next_op < 1 || next_op >= (expression.size() - 1)) {
- _set_error("Parser bug...");
+ _set_parsing_error();
ERR_FAIL_V(nullptr);
}
@@ -6212,7 +6286,7 @@ 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...");
+ _set_parsing_error();
ERR_FAIL_V(nullptr);
}
@@ -6230,7 +6304,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
// can be followed by a unary op in a valid combination,
// due to how precedence works, unaries will always disappear first
- _set_error("Parser bug...");
+ _set_parsing_error();
}
op->arguments.push_back(expression[next_op - 1].node); //expression goes as left
@@ -6243,7 +6317,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
- at += " and ";
+ at += ", ";
}
if (op->arguments[i]->get_datatype() == TYPE_STRUCT) {
at += op->arguments[i]->get_datatype_name();
@@ -6256,7 +6330,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
at += "]";
}
}
- _set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
+ _set_error(vformat(RTR("Invalid arguments to operator '%s': '%s'."), get_operator_text(op->op), at));
return nullptr;
}
@@ -6391,27 +6465,33 @@ ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_
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();
+#ifdef DEBUG_ENABLED
+ Token next;
+#endif // DEBUG_ENABLED
if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_SWITCH) {
if (tk.type != TK_CF_CASE && tk.type != TK_CF_DEFAULT && tk.type != TK_CURLY_BRACKET_CLOSE) {
- _set_error("Switch may contains only case and default blocks");
+ _set_error(vformat(RTR("A switch may only contain '%s' and '%s' blocks."), "case", "default"));
return ERR_PARSE_ERROR;
}
}
bool is_struct = shader->structs.has(tk.text);
+ bool is_var_init = false;
+ bool is_condition = false;
if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block
if (p_just_one) {
- _set_error("Unexpected '}'");
+ _set_expected_error("}");
return ERR_PARSE_ERROR;
}
return OK;
} else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) {
+ is_var_init = true;
+
String struct_name = "";
if (is_struct) {
struct_name = tk.text;
@@ -6421,6 +6501,16 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
#endif // DEBUG_ENABLED
}
+#ifdef DEBUG_ENABLED
+ uint32_t precision_flag = CF_PRECISION_MODIFIER;
+
+ keyword_completion_context = CF_DATATYPE;
+ if (!is_token_precision(tk.type)) {
+ if (!is_struct) {
+ keyword_completion_context |= precision_flag;
+ }
+ }
+#endif // DEBUG_ENABLED
bool is_const = false;
@@ -6442,19 +6532,35 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!is_struct) {
is_struct = shader->structs.has(tk.text); // check again.
}
- if (is_struct && precision != PRECISION_DEFAULT) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
+
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & precision_flag) {
+ keyword_completion_context ^= precision_flag;
}
+#endif // DEBUG_ENABLED
+ }
+
+#ifdef DEBUG_ENABLED
+ if (is_const && _lookup_next(next)) {
+ if (is_token_precision(next.type)) {
+ keyword_completion_context = CF_UNSPECIFIED;
+ }
+ if (is_token_datatype(next.type)) {
+ keyword_completion_context ^= CF_DATATYPE;
+ }
+ }
+#endif // DEBUG_ENABLED
+
+ if (precision != PRECISION_DEFAULT) {
if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
+ _set_error(RTR("Expected variable type after precision modifier."));
return ERR_PARSE_ERROR;
}
}
if (!is_struct) {
if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for variable (samplers not allowed)");
+ _set_error(RTR("Invalid variable type (samplers are not allowed)."));
return ERR_PARSE_ERROR;
}
}
@@ -6465,17 +6571,31 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- Node *vardecl = nullptr;
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
+
int array_size = 0;
bool fixed_array_size = false;
bool first = true;
+ VariableDeclarationNode *vdnode = alloc_node<VariableDeclarationNode>();
+ vdnode->precision = precision;
+ if (is_struct) {
+ vdnode->struct_name = struct_name;
+ vdnode->datatype = TYPE_STRUCT;
+ } else {
+ vdnode->datatype = type;
+ };
+ vdnode->is_const = is_const;
+
do {
bool unknown_size = false;
- Node *size_expr = nullptr;
-
- ArrayDeclarationNode *anode = nullptr;
- ArrayDeclarationNode::Declaration adecl;
+ VariableDeclarationNode::Declaration decl;
tk = _get_token();
@@ -6483,17 +6603,16 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
first = false;
if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected identifier or '[' after datatype.");
+ _set_error(RTR("Expected an identifier or '[' after type."));
return ERR_PARSE_ERROR;
}
if (tk.type == TK_BRACKET_OPEN) {
- Error error = _parse_local_array_size(p_block, p_function_info, size_expr, array_size, unknown_size);
+ Error error = _parse_array_size(p_block, p_function_info, false, &decl.size_expression, &array_size, &unknown_size);
if (error != OK) {
return error;
}
- adecl.single_expression = false;
- adecl.size = array_size;
+ decl.size = array_size;
fixed_array_size = true;
tk = _get_token();
@@ -6501,7 +6620,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier!");
+ _set_error(RTR("Expected an identifier."));
return ERR_PARSE_ERROR;
}
@@ -6509,17 +6628,24 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
ShaderLanguage::IdentifierType 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) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
}
-
- adecl.name = name;
+ decl.name = name;
#ifdef DEBUG_ENABLED
- if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) {
- if (p_block && p_block->parent_function) {
- StringName func_name = p_block->parent_function->name;
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG) && p_block) {
+ FunctionNode *parent_function = nullptr;
+ {
+ BlockNode *block = p_block;
+ while (block && !block->parent_function) {
+ block = block->parent_block;
+ }
+ parent_function = block->parent_function;
+ }
+ if (parent_function) {
+ StringName func_name = parent_function->name;
if (!used_local_vars.has(func_name)) {
used_local_vars.insert(func_name, Map<StringName, Usage>());
@@ -6540,55 +6666,33 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
- bool is_array_decl = var.array_size > 0 || unknown_size;
-
if (tk.type == TK_BRACKET_OPEN) {
- if (is_array_decl) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
- }
-
if (RenderingServer::get_singleton()->is_low_end() && is_const) {
- _set_error("Local const arrays are supported only on high-end platform!");
+ _set_error(RTR("Local const arrays are only supported on high-end platforms."));
return ERR_PARSE_ERROR;
}
- Error error = _parse_local_array_size(p_block, p_function_info, size_expr, var.array_size, unknown_size);
+ Error error = _parse_array_size(p_block, p_function_info, false, &decl.size_expression, &var.array_size, &unknown_size);
if (error != OK) {
return error;
}
- adecl.single_expression = false;
- adecl.size = var.array_size;
+ decl.size = var.array_size;
array_size = var.array_size;
- is_array_decl = true;
tk = _get_token();
}
-
- if (is_array_decl) {
- {
- anode = alloc_node<ArrayDeclarationNode>();
-
- if (is_struct) {
- anode->struct_name = struct_name;
- anode->datatype = TYPE_STRUCT;
- } else {
- anode->datatype = type;
- }
-
- anode->precision = precision;
- anode->is_const = is_const;
- anode->size_expression = size_expr;
-
- vardecl = (Node *)anode;
- }
-
+#ifdef DEBUG_ENABLED
+ if (var.type == DataType::TYPE_BOOL) {
+ keyword_completion_context = CF_BOOLEAN;
+ }
+#endif // DEBUG_ENABLED
+ if (var.array_size > 0 || unknown_size) {
bool full_def = false;
if (tk.type == TK_OP_ASSIGN) {
if (RenderingServer::get_singleton()->is_low_end()) {
- _set_error("Array initialization is supported only on high-end platform!");
+ _set_error(RTR("Array initialization is only supported on high-end platforms."));
return ERR_PARSE_ERROR;
}
@@ -6600,11 +6704,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
- _set_error("Expected correct array initializer!");
+ _set_error(RTR("Expected array initializer."));
return ERR_PARSE_ERROR;
} else {
if (unknown_size) {
- adecl.size = n->get_array_size();
+ decl.size = n->get_array_size();
var.array_size = n->get_array_size();
}
@@ -6612,15 +6716,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- adecl.single_expression = true;
- adecl.initializer.push_back(n);
+ decl.single_expression = true;
+ decl.initializer.push_back(n);
}
tk = _get_token();
} else {
if (tk.type != TK_CURLY_BRACKET_OPEN) {
if (unknown_size) {
- _set_error("Expected '{'");
+ _set_expected_error("{");
return ERR_PARSE_ERROR;
}
@@ -6630,12 +6734,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (is_token_precision(tk.type)) {
precision2 = get_token_precision(tk.type);
tk = _get_token();
- if (shader->structs.has(tk.text)) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
+ _set_error(RTR("Expected data type after precision modifier."));
return ERR_PARSE_ERROR;
}
}
@@ -6648,83 +6748,64 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
struct_name2 = tk.text;
} else {
if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
+ _set_error(RTR("Invalid data type for the array."));
return ERR_PARSE_ERROR;
}
type2 = get_token_datatype(tk.type);
}
+ if (precision2 != PRECISION_DEFAULT && _validate_precision(type2, precision2) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
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) {
+ bool is_unknown_size = false;
+ Error error = _parse_array_size(p_block, p_function_info, false, nullptr, &array_size2, &is_unknown_size);
+ if (error != OK) {
+ return error;
+ }
+ if (is_unknown_size) {
array_size2 = var.array_size;
- tk = _get_token();
- } else {
- _set_tkpos(pos2);
-
- 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;
- }
-
- 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();
- }
}
+ tk = _get_token();
} else {
- _set_error("Expected '['");
+ _set_expected_error("[");
return ERR_PARSE_ERROR;
}
if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
- String error_str = "Cannot convert from '";
+ String from;
if (precision2 != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision2);
- error_str += " ";
+ from += get_precision_name(precision2);
+ from += " ";
}
if (type2 == TYPE_STRUCT) {
- error_str += struct_name2;
+ from += struct_name2;
} else {
- error_str += get_datatype_name(type2);
+ from += get_datatype_name(type2);
}
- error_str += "[";
- error_str += itos(array_size2);
- error_str += "]'";
- error_str += " to '";
+ from += "[";
+ from += itos(array_size2);
+ from += "]'";
+
+ String to;
if (precision != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision);
- error_str += " ";
+ to += get_precision_name(precision);
+ to += " ";
}
if (type == TYPE_STRUCT) {
- error_str += struct_name;
+ to += struct_name;
} else {
- error_str += get_datatype_name(type);
+ to += get_datatype_name(type);
}
- error_str += "[";
- error_str += itos(var.array_size);
- error_str += "]'";
- _set_error(error_str);
+ to += "[";
+ to += itos(var.array_size);
+ to += "]'";
+
+ _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to));
return ERR_PARSE_ERROR;
}
}
@@ -6733,13 +6814,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (unknown_size) {
if (!curly) {
- _set_error("Expected '{'");
+ _set_expected_error("{");
return ERR_PARSE_ERROR;
}
} else {
if (full_def) {
if (curly) {
- _set_error("Expected '('");
+ _set_expected_error("(");
return ERR_PARSE_ERROR;
}
}
@@ -6752,8 +6833,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- if (anode->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression");
+ if (is_const && n->type == Node::TYPE_OPERATOR && static_cast<OperatorNode *>(n)->op == OP_CALL) {
+ _set_error(RTR("Expected a constant expression."));
return ERR_PARSE_ERROR;
}
@@ -6763,28 +6844,28 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type == TK_COMMA) {
- adecl.initializer.push_back(n);
+ decl.initializer.push_back(n);
continue;
} else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
- adecl.initializer.push_back(n);
+ decl.initializer.push_back(n);
break;
} else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
- adecl.initializer.push_back(n);
+ decl.initializer.push_back(n);
break;
} else {
if (curly) {
- _set_error("Expected '}' or ','");
+ _set_expected_error("}", ",");
} else {
- _set_error("Expected ')' or ','");
+ _set_expected_error(")", ",");
}
return ERR_PARSE_ERROR;
}
}
if (unknown_size) {
- adecl.size = adecl.initializer.size();
- var.array_size = adecl.initializer.size();
- } else if (adecl.initializer.size() != var.array_size) {
- _set_error("Array size mismatch");
+ decl.size = decl.initializer.size();
+ var.array_size = decl.initializer.size();
+ } else if (decl.initializer.size() != var.array_size) {
+ _set_error(RTR("Array size mismatch."));
return ERR_PARSE_ERROR;
}
tk = _get_token();
@@ -6792,48 +6873,31 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
} else {
if (unknown_size) {
- _set_error("Expected array initialization");
+ _set_error(RTR("Expected array initialization."));
return ERR_PARSE_ERROR;
}
- if (anode->is_const) {
- _set_error("Expected initialization of constant");
+ if (is_const) {
+ _set_error(RTR("Expected initialization of constant."));
return ERR_PARSE_ERROR;
}
}
array_size = var.array_size;
- anode->declarations.push_back(adecl);
} else if (tk.type == TK_OP_ASSIGN) {
- VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
- if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
- } else {
- node->datatype = type;
- }
- node->precision = precision;
- node->is_const = is_const;
- vardecl = (Node *)node;
-
- VariableDeclarationNode::Declaration decl;
- decl.name = name;
- decl.initializer = nullptr;
-
//variable created with assignment! must parse an expression
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) {
- OperatorNode *op = ((OperatorNode *)n);
+ if (is_const && n->type == Node::TYPE_OPERATOR && static_cast<OperatorNode *>(n)->op == OP_CALL) {
+ OperatorNode *op = static_cast<OperatorNode *>(n);
for (int i = 1; i < op->arguments.size(); i++) {
if (!_check_node_constness(op->arguments[i])) {
- _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ _set_error(vformat(RTR("Expected constant expression for argument %d of function call after '='."), i - 1));
return ERR_PARSE_ERROR;
}
}
}
- decl.initializer = n;
if (n->type == Node::TYPE_CONSTANT) {
ConstantNode *const_node = static_cast<ConstantNode *>(n);
@@ -6845,49 +6909,34 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return ERR_PARSE_ERROR;
}
+
+ decl.initializer.push_back(n);
tk = _get_token();
- node->declarations.push_back(decl);
} else {
if (is_const) {
- _set_error("Expected initialization of constant");
+ _set_error(RTR("Expected initialization of constant."));
return ERR_PARSE_ERROR;
}
-
- VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
- if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
- } else {
- node->datatype = type;
- }
- node->precision = precision;
- vardecl = (Node *)node;
-
- VariableDeclarationNode::Declaration decl;
- decl.name = name;
- decl.initializer = nullptr;
- node->declarations.push_back(decl);
}
- p_block->statements.push_back(vardecl);
+ vdnode->declarations.push_back(decl);
p_block->variables[name] = var;
if (!fixed_array_size) {
array_size = 0;
}
- if (tk.type == TK_COMMA) {
- if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) {
- _set_error("Multiple declarations in 'for' loop are not implemented yet.");
- return ERR_PARSE_ERROR;
- }
- } else if (tk.type == TK_SEMICOLON) {
+ if (tk.type == TK_SEMICOLON) {
break;
- } else {
- _set_error("Expected ',' or ';' after variable");
+ } else if (tk.type != TK_COMMA) {
+ _set_expected_error(",", ";");
return ERR_PARSE_ERROR;
}
} while (tk.type == TK_COMMA); //another variable
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_BLOCK;
+#endif // DEBUG_ENABLED
+ p_block->statements.push_back(static_cast<Node *>(vdnode));
} else if (tk.type == TK_CURLY_BRACKET_OPEN) {
//a sub block, just because..
BlockNode *block = alloc_node<BlockNode>();
@@ -6900,25 +6949,31 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
//if () {}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after if");
+ _set_expected_after_error("(", "if");
return ERR_PARSE_ERROR;
}
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_IF;
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_IF_DECL;
+#endif // DEBUG_ENABLED
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_BLOCK;
+#endif // DEBUG_ENABLED
if (n->get_datatype() != TYPE_BOOL) {
- _set_error("Expected boolean expression");
+ _set_error(RTR("Expected a boolean expression."));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
+ _set_expected_error(")");
return ERR_PARSE_ERROR;
}
@@ -6948,14 +7003,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
} 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!");
+ _set_error(vformat(RTR("The '%s' operator is only supported on high-end platforms."), "switch"));
return ERR_PARSE_ERROR;
}
// switch() {}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after switch");
+ _set_expected_after_error("(", "switch");
return ERR_PARSE_ERROR;
}
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
@@ -6965,17 +7020,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
if (n->get_datatype() != TYPE_INT) {
- _set_error("Expected integer expression");
+ _set_error(RTR("Expected an integer expression."));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
+ _set_expected_error(")");
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{' after switch statement");
+ _set_expected_after_error("{", "switch");
return ERR_PARSE_ERROR;
}
BlockNode *switch_block = alloc_node<BlockNode>();
@@ -6996,10 +7051,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) {
if (prev_type == TK_CF_DEFAULT) {
if (tk.type == TK_CF_CASE) {
- _set_error("Cases must be defined before default case.");
+ _set_error(RTR("Cases must be defined before default case."));
return ERR_PARSE_ERROR;
} else if (prev_type == TK_CF_DEFAULT) {
- _set_error("Default case must be defined only once.");
+ _set_error(RTR("Default case must be defined only once."));
return ERR_PARSE_ERROR;
}
}
@@ -7009,7 +7064,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
} else {
Set<int> constants;
for (int i = 0; i < switch_block->statements.size(); i++) { // Checks for duplicates.
- ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i];
+ ControlFlowNode *flow = static_cast<ControlFlowNode *>(switch_block->statements[i]);
if (flow) {
if (flow->flow_op == FLOW_OP_CASE) {
if (flow->expressions[0]->type == Node::TYPE_CONSTANT) {
@@ -7018,7 +7073,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
if (constants.has(cn->values[0].sint)) {
- _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'");
+ _set_error(vformat(RTR("Duplicated case label: %d."), cn->values[0].sint));
return ERR_PARSE_ERROR;
}
constants.insert(cn->values[0].sint);
@@ -7030,7 +7085,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
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) + "'");
+ _set_error(vformat(RTR("Duplicated case label: %d."), v.sint));
return ERR_PARSE_ERROR;
}
constants.insert(v.sint);
@@ -7057,7 +7112,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
- _set_error("case must be placed within switch block");
+ _set_error(vformat(RTR("'%s' must be placed within a '%s' block."), "case", "switch"));
return ERR_PARSE_ERROR;
}
@@ -7086,7 +7141,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
if (!correct_constant_expression) {
- _set_error("Expected integer constant");
+ _set_error(RTR("Expected an integer constant."));
return ERR_PARSE_ERROR;
}
@@ -7110,7 +7165,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type != TK_COLON) {
- _set_error("Expected ':'");
+ _set_expected_error(":");
return ERR_PARSE_ERROR;
}
@@ -7138,14 +7193,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
- _set_error("default must be placed within switch block");
+ _set_error(vformat(RTR("'%s' must be placed within a '%s' block."), "default", "switch"));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_COLON) {
- _set_error("Expected ':'");
+ _set_expected_error(":");
return ERR_PARSE_ERROR;
}
@@ -7182,14 +7237,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type != TK_CF_WHILE) {
- _set_error("Expected while after do");
+ _set_expected_after_error("while", "do");
return ERR_PARSE_ERROR;
}
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after while");
+ _set_expected_after_error("(", "while");
return ERR_PARSE_ERROR;
}
@@ -7206,7 +7261,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
+ _set_expected_error(")");
return ERR_PARSE_ERROR;
}
if (!is_do) {
@@ -7227,7 +7282,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
+ _set_expected_error(";");
return ERR_PARSE_ERROR;
}
}
@@ -7235,7 +7290,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
// for() {}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after for");
+ _set_expected_after_error("(", "for");
return ERR_PARSE_ERROR;
}
@@ -7243,43 +7298,42 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
cf->flow_op = FLOW_OP_FOR;
BlockNode *init_block = alloc_node<BlockNode>();
- init_block->block_type = BlockNode::BLOCK_TYPE_FOR;
+ init_block->block_type = BlockNode::BLOCK_TYPE_FOR_INIT;
init_block->parent_block = p_block;
init_block->single_statement = true;
cf->blocks.push_back(init_block);
- if (_parse_block(init_block, p_function_info, true, false, false) != OK) {
- return ERR_PARSE_ERROR;
- }
-
- Node *n = _parse_and_reduce_expression(init_block, p_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
- if (n->get_datatype() != TYPE_BOOL) {
- _set_error("Middle expression is expected to be boolean.");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after middle expression");
- return ERR_PARSE_ERROR;
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_DATATYPE;
+#endif // DEBUG_ENABLED
+ Error err = _parse_block(init_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
- cf->expressions.push_back(n);
-
- n = _parse_and_reduce_expression(init_block, p_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
+ BlockNode *condition_block = alloc_node<BlockNode>();
+ condition_block->block_type = BlockNode::BLOCK_TYPE_FOR_CONDITION;
+ condition_block->parent_block = init_block;
+ condition_block->single_statement = true;
+ condition_block->use_comma_between_statements = true;
+ cf->blocks.push_back(condition_block);
+ err = _parse_block(condition_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
- cf->expressions.push_back(n);
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after third expression");
- return ERR_PARSE_ERROR;
+ BlockNode *expression_block = alloc_node<BlockNode>();
+ expression_block->block_type = BlockNode::BLOCK_TYPE_FOR_EXPRESSION;
+ expression_block->parent_block = init_block;
+ expression_block->single_statement = true;
+ expression_block->use_comma_between_statements = true;
+ cf->blocks.push_back(expression_block);
+ err = _parse_block(expression_block, p_function_info, true, false, false);
+ if (err != OK) {
+ return err;
}
BlockNode *block = alloc_node<BlockNode>();
@@ -7287,8 +7341,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_function_info, true, true, true);
- if (err) {
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_BLOCK;
+#endif // DEBUG_ENABLED
+ err = _parse_block(block, p_function_info, true, true, true);
+ if (err != OK) {
return err;
}
@@ -7301,12 +7358,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (!b) {
- _set_error("Bug");
+ _set_parsing_error();
return ERR_BUG;
}
if (b && b->parent_function && p_function_info.main_function) {
- _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
+ _set_error(vformat(RTR("Using '%s' in the '%s' processor function is incorrect."), "return", b->parent_function->name));
return ERR_PARSE_ERROR;
}
@@ -7325,28 +7382,40 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
+ _set_error(vformat(RTR("Expected '%s' with an expression of type '%s'."), "return", (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string));
return ERR_PARSE_ERROR;
}
} else {
_set_tkpos(pos); //rollback, wants expression
+#ifdef DEBUG_ENABLED
+ if (b->parent_function->return_type == DataType::TYPE_BOOL) {
+ keyword_completion_context = CF_BOOLEAN;
+ }
+#endif // DEBUG_ENABLED
+
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() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) {
- _set_error("Expected return with an expression of type '" + (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
+ _set_error(vformat(RTR("Expected return with an expression of type '%s'."), (!return_struct_name.is_empty() ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after return expression");
+ _set_expected_after_error(";", "return");
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ if (b->parent_function->return_type == DataType::TYPE_BOOL) {
+ keyword_completion_context = CF_BLOCK;
+ }
+#endif // DEBUG_ENABLED
+
flow->expressions.push_back(expr);
}
@@ -7366,12 +7435,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
b = b->parent_block;
}
if (!b) {
- _set_error("Bug");
+ _set_parsing_error();
return ERR_BUG;
}
if (!b->parent_function->can_discard) {
- _set_error("Use of 'discard' is not allowed here.");
+ _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard"));
return ERR_PARSE_ERROR;
}
@@ -7381,14 +7450,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after discard");
+ _set_expected_after_error(";", "discard");
return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
} else if (tk.type == TK_CF_BREAK) {
if (!p_can_break) {
- _set_error("'break' is not allowed outside of a loop or 'switch' statement");
+ _set_error(vformat(RTR("'%s' is not allowed outside of a loop or '%s' statement."), "break", "switch"));
return ERR_PARSE_ERROR;
}
@@ -7398,7 +7467,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after break");
+ _set_expected_after_error(";", "break");
return ERR_PARSE_ERROR;
}
@@ -7414,7 +7483,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
} else if (tk.type == TK_CF_CONTINUE) {
if (!p_can_continue) {
- _set_error("'continue' is not allowed outside of a loop");
+ _set_error(vformat(RTR("'%s' is not allowed outside of a loop."), "continue"));
return ERR_PARSE_ERROR;
}
@@ -7425,7 +7494,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
//all is good
- _set_error("Expected ';' after continue");
+ _set_expected_after_error(";", "continue");
return ERR_PARSE_ERROR;
}
@@ -7438,11 +7507,52 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!expr) {
return ERR_PARSE_ERROR;
}
+ is_condition = expr->type == Node::TYPE_OPERATOR && expr->get_datatype() == TYPE_BOOL;
+
+ if (expr->type == Node::TYPE_OPERATOR) {
+ OperatorNode *op = static_cast<OperatorNode *>(expr);
+ if (op->op == OP_EMPTY) {
+ is_var_init = true;
+ is_condition = true;
+ }
+ }
+
p_block->statements.push_back(expr);
tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after statement");
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION) {
+ if (tk.type == TK_COMMA) {
+ if (!is_condition) {
+ _set_error(RTR("The middle expression is expected to be a boolean operator."));
+ return ERR_PARSE_ERROR;
+ }
+ continue;
+ }
+ if (tk.type != TK_SEMICOLON) {
+ _set_expected_error(",", ";");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_EXPRESSION) {
+ if (tk.type == TK_COMMA) {
+ continue;
+ }
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_expected_error(",", ")");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (tk.type != TK_SEMICOLON) {
+ _set_expected_error(";");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (p_block) {
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_INIT && !is_var_init) {
+ _set_error(RTR("The left expression is expected to be a variable declaration."));
+ return ERR_PARSE_ERROR;
+ }
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR_CONDITION && !is_condition) {
+ _set_error(RTR("The middle expression is expected to be a boolean operator."));
return ERR_PARSE_ERROR;
}
}
@@ -7481,6 +7591,25 @@ String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
return "";
}
+Error ShaderLanguage::_validate_precision(DataType p_type, DataPrecision p_precision) {
+ switch (p_type) {
+ case TYPE_STRUCT: {
+ _set_error(RTR("The precision modifier cannot be used on structs."));
+ return FAILED;
+ } break;
+ case TYPE_BOOL:
+ case TYPE_BVEC2:
+ case TYPE_BVEC3:
+ case TYPE_BVEC4: {
+ _set_error(RTR("The precision modifier cannot be used on boolean types."));
+ return FAILED;
+ } break;
+ default:
+ break;
+ }
+ return OK;
+}
+
Error ShaderLanguage::_validate_datatype(DataType p_type) {
if (RenderingServer::get_singleton()->is_low_end()) {
bool invalid_type = false;
@@ -7503,7 +7632,7 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) {
}
if (invalid_type) {
- _set_error(vformat("\"%s\" type is supported only on high-end platform!", get_datatype_name(p_type)));
+ _set_error(vformat(RTR("The \"%s\" type is only supported on high-end platforms."), get_datatype_name(p_type)));
return ERR_UNAVAILABLE;
}
}
@@ -7513,25 +7642,23 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) {
Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Set<String> &p_shader_types) {
Token tk = _get_token();
TkPos prev_pos;
+ Token next;
if (tk.type != TK_SHADER_TYPE) {
- _set_error("Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
+ _set_error(vformat(RTR("Expected '%s' at the beginning of shader. Valid types are: %s."), "shader_type", _get_shader_type_list(p_shader_types)));
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
- tk = _get_token();
-
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
+ _get_completable_identifier(nullptr, COMPLETION_SHADER_TYPE, shader_type_identifier);
+ if (shader_type_identifier == StringName()) {
+ _set_error(vformat(RTR("Expected an identifier after '%s', indicating the type of shader. Valid types are: %s."), "shader_type", _get_shader_type_list(p_shader_types)));
return ERR_PARSE_ERROR;
}
-
- String shader_type_identifier;
-
- shader_type_identifier = tk.text;
-
if (!p_shader_types.has(shader_type_identifier)) {
- _set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
+ _set_error(vformat(RTR("Invalid shader type. Valid types are: %s"), _get_shader_type_list(p_shader_types)));
return ERR_PARSE_ERROR;
}
prev_pos = _get_tkpos();
@@ -7539,16 +7666,34 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type != TK_SEMICOLON) {
_set_tkpos(prev_pos);
- _set_error("Expected ';' after 'shader_type <type>'.");
+ _set_expected_after_error(";", "shader_type " + String(shader_type_identifier));
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_GLOBAL_SPACE;
+#endif // DEBUG_ENABLED
tk = _get_token();
int texture_uniforms = 0;
int texture_binding = 0;
int uniforms = 0;
int instance_index = 0;
+#ifdef DEBUG_ENABLED
+ uint64_t uniform_buffer_size = 0;
+ uint64_t max_uniform_buffer_size = 0;
+ int uniform_buffer_exceeded_line = -1;
+
+ bool check_device_limit_warnings = false;
+ {
+ RenderingDevice *device = RenderingDevice::get_singleton();
+ if (device != nullptr) {
+ check_device_limit_warnings = check_warnings && HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
+
+ max_uniform_buffer_size = device->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
+ }
+ }
+#endif // DEBUG_ENABLED
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
stages = &p_functions;
@@ -7564,14 +7709,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_get_completable_identifier(nullptr, COMPLETION_RENDER_MODE, mode);
if (mode == StringName()) {
- _set_error("Expected identifier for render mode");
+ _set_error(RTR("Expected an identifier for render mode."));
return ERR_PARSE_ERROR;
}
const String smode = String(mode);
- if (shader->render_modes.find(mode) != -1) {
- _set_error(vformat("Duplicated render mode: '%s'.", smode));
+ if (shader->render_modes.has(mode)) {
+ _set_error(vformat(RTR("Duplicated render mode: '%s'."), smode));
return ERR_PARSE_ERROR;
}
@@ -7583,11 +7728,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (smode.begins_with(name)) {
if (!info.options.is_empty()) {
- if (info.options.find(smode.substr(name.length() + 1)) != -1) {
+ if (info.options.has(smode.substr(name.length() + 1))) {
found = true;
if (defined_modes.has(name)) {
- _set_error(vformat("Redefinition of render mode: '%s'. The %s mode has already been set to '%s'.", smode, name, defined_modes[name]));
+ _set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, defined_modes[name]));
return ERR_PARSE_ERROR;
}
defined_modes.insert(name, smode);
@@ -7601,7 +7746,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (!found) {
- _set_error(vformat("Invalid render mode: '%s'.", smode));
+ _set_error(vformat(RTR("Invalid render mode: '%s'."), smode));
return ERR_PARSE_ERROR;
}
@@ -7613,7 +7758,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else if (tk.type == TK_SEMICOLON) {
break; //done
} else {
- _set_error("Unexpected token: " + get_token_text(tk));
+ _set_error(vformat(RTR("Unexpected token: '%s'."), get_token_text(tk)));
return ERR_PARSE_ERROR;
}
}
@@ -7621,21 +7766,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
case TK_STRUCT: {
ShaderNode::Struct st;
DataType type;
-
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
st.name = tk.text;
if (shader->constants.has(st.name) || shader->structs.has(st.name)) {
- _set_error("Redefinition of '" + String(st.name) + "'");
+ _set_redefinition_error(String(st.name));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{'");
+ _set_expected_error("{");
return ERR_PARSE_ERROR;
}
} else {
- _set_error("Expected struct identifier!");
+ _set_error(RTR("Expected a struct identifier."));
return ERR_PARSE_ERROR;
}
@@ -7644,25 +7791,31 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
int member_count = 0;
Set<String> member_names;
+
while (true) { // variables list
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_DATATYPE | CF_PRECISION_MODIFIER;
+#endif // DEBUG_ENABLED
+
tk = _get_token();
if (tk.type == TK_CURLY_BRACKET_CLOSE) {
break;
}
StringName struct_name = "";
bool struct_dt = false;
- bool use_precision = false;
- DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
+ DataPrecision precision = PRECISION_DEFAULT;
if (tk.type == TK_STRUCT) {
- _set_error("nested structs are not allowed!");
+ _set_error(RTR("Nested structs are not allowed."));
return ERR_PARSE_ERROR;
}
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- use_precision = true;
tk = _get_token();
+#ifdef DEBUG_ENABLED
+ keyword_completion_context ^= CF_PRECISION_MODIFIER;
+#endif // DEBUG_ENABLED
}
if (shader->structs.has(tk.text)) {
@@ -7673,25 +7826,25 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
#endif // DEBUG_ENABLED
struct_dt = true;
- if (use_precision) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
}
if (!is_token_datatype(tk.type) && !struct_dt) {
- _set_error("Expected datatype.");
+ _set_error(RTR("Expected data type."));
return ERR_PARSE_ERROR;
} else {
type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
- if (is_sampler_type(type)) {
- _set_error("sampler datatype not allowed here");
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
return ERR_PARSE_ERROR;
- } else if (type == TYPE_VOID) {
- _set_error("void datatype not allowed here");
+ }
+
+ if (type == TYPE_VOID || is_sampler_type(type)) {
+ _set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type)));
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
bool first = true;
bool fixed_array_size = false;
@@ -7704,12 +7857,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
first = false;
if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected identifier or '['.");
+ _set_error(RTR("Expected an identifier or '['."));
return ERR_PARSE_ERROR;
}
if (tk.type == TK_BRACKET_OPEN) {
- Error error = _parse_global_array_size(array_size, constants);
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &array_size, nullptr);
if (error != OK) {
return error;
}
@@ -7719,7 +7872,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier!");
+ _set_error(RTR("Expected an identifier."));
return ERR_PARSE_ERROR;
}
@@ -7731,14 +7884,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
member->array_size = array_size;
if (member_names.has(member->name)) {
- _set_error("Redefinition of '" + String(member->name) + "'");
+ _set_redefinition_error(String(member->name));
return ERR_PARSE_ERROR;
}
member_names.insert(member->name);
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- Error error = _parse_global_array_size(member->array_size, constants);
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &member->array_size, nullptr);
if (error != OK) {
return error;
}
@@ -7750,7 +7903,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) {
- _set_error("Expected ',' or ';' after struct member.");
+ _set_expected_error(",", ";");
return ERR_PARSE_ERROR;
}
@@ -7760,15 +7913,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
}
if (member_count == 0) {
- _set_error("Empty structs are not allowed!");
+ _set_error(RTR("Empty structs are not allowed."));
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
+ _set_expected_error(";");
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_GLOBAL_SPACE;
+#endif // DEBUG_ENABLED
+
shader->structs[st.name] = st;
shader->vstructs.push_back(st); // struct's order is important!
#ifdef DEBUG_ENABLED
@@ -7778,19 +7938,35 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
#endif // DEBUG_ENABLED
} break;
case TK_GLOBAL: {
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNIFORM_KEYWORD;
+ if (_lookup_next(next)) {
+ if (next.type == TK_UNIFORM) {
+ keyword_completion_context ^= CF_UNIFORM_KEYWORD;
+ }
+ }
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type != TK_UNIFORM) {
- _set_error("Expected 'uniform' after 'global'");
+ _set_expected_after_error("uniform", "global");
return ERR_PARSE_ERROR;
}
uniform_scope = ShaderNode::Uniform::SCOPE_GLOBAL;
};
[[fallthrough]];
case TK_INSTANCE: {
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNIFORM_KEYWORD;
+ if (_lookup_next(next)) {
+ if (next.type == TK_UNIFORM) {
+ keyword_completion_context ^= CF_UNIFORM_KEYWORD;
+ }
+ }
+#endif // DEBUG_ENABLED
if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) {
tk = _get_token();
if (tk.type != TK_UNIFORM) {
- _set_error("Expected 'uniform' after 'instance'");
+ _set_expected_after_error("uniform", "instance");
return ERR_PARSE_ERROR;
}
uniform_scope = ShaderNode::Uniform::SCOPE_INSTANCE;
@@ -7800,15 +7976,15 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
case TK_UNIFORM:
case TK_VARYING: {
bool uniform = tk.type == TK_UNIFORM;
-
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
if (!uniform) {
if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") {
- _set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier));
+ _set_error(vformat(RTR("Varyings cannot be used in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
}
-
- bool precision_defined = false;
DataPrecision precision = PRECISION_DEFAULT;
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
DataType type;
@@ -7816,61 +7992,126 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
int array_size = 0;
tk = _get_token();
+#ifdef DEBUG_ENABLED
+ bool temp_error = false;
+ uint32_t datatype_flag;
+
+ if (!uniform) {
+ datatype_flag = CF_VARYING_TYPE;
+ keyword_completion_context = CF_INTERPOLATION_QUALIFIER | CF_PRECISION_MODIFIER | datatype_flag;
+
+ if (_lookup_next(next)) {
+ if (is_token_interpolation(next.type)) {
+ keyword_completion_context ^= (CF_INTERPOLATION_QUALIFIER | datatype_flag);
+ } else if (is_token_precision(next.type)) {
+ keyword_completion_context ^= (CF_PRECISION_MODIFIER | datatype_flag);
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context ^= datatype_flag;
+ }
+ }
+ } else {
+ datatype_flag = CF_UNIFORM_TYPE;
+ keyword_completion_context = CF_PRECISION_MODIFIER | datatype_flag;
+
+ if (_lookup_next(next)) {
+ if (is_token_precision(next.type)) {
+ keyword_completion_context ^= (CF_PRECISION_MODIFIER | datatype_flag);
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context ^= datatype_flag;
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
+
if (is_token_interpolation(tk.type)) {
if (uniform) {
- _set_error("Interpolation qualifiers are not supported for uniforms!");
+ _set_error(RTR("Interpolation qualifiers are not supported for uniforms."));
+#ifdef DEBUG_ENABLED
+ temp_error = true;
+#else
return ERR_PARSE_ERROR;
+#endif // DEBUG_ENABLED
}
interpolation = get_token_interpolation(tk.type);
tk = _get_token();
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & CF_INTERPOLATION_QUALIFIER) {
+ keyword_completion_context ^= CF_INTERPOLATION_QUALIFIER;
+ }
+ if (_lookup_next(next)) {
+ if (is_token_precision(next.type)) {
+ keyword_completion_context ^= CF_PRECISION_MODIFIER;
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context ^= datatype_flag;
+ }
+ }
+ if (temp_error) {
+ return ERR_PARSE_ERROR;
+ }
+#endif // DEBUG_ENABLED
}
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
- precision_defined = true;
tk = _get_token();
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & CF_INTERPOLATION_QUALIFIER) {
+ keyword_completion_context ^= CF_INTERPOLATION_QUALIFIER;
+ }
+ if (keyword_completion_context & CF_PRECISION_MODIFIER) {
+ keyword_completion_context ^= CF_PRECISION_MODIFIER;
+ }
+ if (_lookup_next(next)) {
+ if (is_token_datatype(next.type)) {
+ keyword_completion_context = CF_UNSPECIFIED;
+ }
+ }
+#endif // DEBUG_ENABLED
}
if (shader->structs.has(tk.text)) {
if (uniform) {
- if (precision_defined) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- _set_error("struct datatype is not yet supported for uniforms!");
+ _set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
return ERR_PARSE_ERROR;
} else {
- _set_error("struct datatype not allowed here");
+ _set_error(vformat(RTR("The '%s' data type not allowed here."), "struct"));
return ERR_PARSE_ERROR;
}
}
if (!is_token_datatype(tk.type)) {
- _set_error("Expected datatype. ");
+ _set_error(RTR("Expected data type."));
return ERR_PARSE_ERROR;
}
type = get_token_datatype(tk.type);
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
if (type == TYPE_VOID) {
- _set_error("void datatype not allowed here");
+ _set_error(vformat(RTR("The '%s' data type is not allowed here."), "void"));
return ERR_PARSE_ERROR;
}
if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
- _set_error("Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 or array of these types allowed.");
+ _set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed."));
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected identifier or '['.");
+ _set_error(RTR("Expected an identifier or '['."));
return ERR_PARSE_ERROR;
}
if (tk.type == TK_BRACKET_OPEN) {
- Error error = _parse_global_array_size(array_size, constants);
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &array_size, nullptr);
if (error != OK) {
return error;
}
@@ -7878,7 +8119,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier!");
+ _set_error(RTR("Expected an identifier."));
return ERR_PARSE_ERROR;
}
@@ -7886,26 +8127,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
name = tk.text;
if (_find_identifier(nullptr, false, constants, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
if (has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
if (uniform) {
- if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor.
//validate global uniform
DataType gvtype = global_var_get_type_func(name);
if (gvtype == TYPE_MAX) {
- _set_error("Global uniform '" + String(name) + "' does not exist. Create it in Project Settings.");
+ _set_error(vformat(RTR("Global uniform '%s' does not exist. Create it in Project Settings."), String(name)));
return ERR_PARSE_ERROR;
}
if (type != gvtype) {
- _set_error("Global uniform '" + String(name) + "' must be of type '" + get_datatype_name(gvtype) + "'.");
+ _set_error(vformat(RTR("Global uniform '%s' must be of type '%s'."), String(name), get_datatype_name(gvtype)));
return ERR_PARSE_ERROR;
}
}
@@ -7918,7 +8159,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- Error error = _parse_global_array_size(uniform2.array_size, constants);
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &uniform2.array_size, nullptr);
if (error != OK) {
return error;
}
@@ -7927,7 +8168,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (is_sampler_type(type)) {
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
- _set_error("Uniforms with 'instance' qualifiers can't be of sampler type.");
+ _set_error(vformat(RTR("The '%s' qualifier is not supported for sampler types."), "SCOPE_INSTANCE"));
return ERR_PARSE_ERROR;
}
uniform2.texture_order = texture_uniforms++;
@@ -7943,22 +8184,40 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
} else {
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE && (type == TYPE_MAT2 || type == TYPE_MAT3 || type == TYPE_MAT4)) {
- _set_error("Uniforms with 'instance' qualifiers can't be of matrix type.");
+ _set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE"));
return ERR_PARSE_ERROR;
}
uniform2.texture_order = -1;
if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
uniform2.order = uniforms++;
+#ifdef DEBUG_ENABLED
+ if (check_device_limit_warnings) {
+ if (uniform2.array_size > 0) {
+ int size = get_datatype_size(uniform2.type) * uniform2.array_size;
+ int m = (16 * uniform2.array_size);
+ if ((size % m) != 0U) {
+ size += m - (size % m);
+ }
+ uniform_buffer_size += size;
+ } else {
+ uniform_buffer_size += get_datatype_size(uniform2.type);
+ }
+
+ if (uniform_buffer_exceeded_line == -1 && uniform_buffer_size > max_uniform_buffer_size) {
+ uniform_buffer_exceeded_line = tk_line;
+ }
+ }
+#endif // DEBUG_ENABLED
}
}
if (uniform2.array_size > 0) {
if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
- _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!");
+ _set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_GLOBAL"));
return ERR_PARSE_ERROR;
}
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
- _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!");
+ _set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_INSTANCE"));
return ERR_PARSE_ERROR;
}
}
@@ -7976,13 +8235,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
completion_line = tk.line;
if (!is_token_hint(tk.type)) {
- _set_error("Expected valid type hint after ':'.");
+ _set_error(RTR("Expected valid type hint after ':'."));
return ERR_PARSE_ERROR;
}
if (uniform2.array_size > 0) {
if (tk.type != TK_HINT_COLOR) {
- _set_error("This hint is not yet supported for uniform arrays!");
+ _set_error(RTR("This hint is not supported for uniform arrays."));
return ERR_PARSE_ERROR;
}
}
@@ -8012,21 +8271,21 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) {
uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO;
} else if (tk.type == TK_HINT_COLOR) {
- if (type != TYPE_VEC4) {
- _set_error("Color hint is for vec4 only");
+ if (type != TYPE_VEC3 && type != TYPE_VEC4) {
+ _set_error(vformat(RTR("Color hint is for '%s' or '%s' only."), "vec3", "vec4"));
return ERR_PARSE_ERROR;
}
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");
+ _set_error(vformat(RTR("Range hint is for '%s' and '%s' only."), "float", "int"));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after hint_range");
+ _set_expected_after_error("(", "hint_range");
return ERR_PARSE_ERROR;
}
@@ -8040,7 +8299,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
- _set_error("Expected integer constant");
+ _set_error(RTR("Expected an integer constant."));
return ERR_PARSE_ERROR;
}
@@ -8050,7 +8309,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type != TK_COMMA) {
- _set_error("Expected ',' after integer constant");
+ _set_error(RTR("Expected ',' after integer constant."));
return ERR_PARSE_ERROR;
}
@@ -8064,7 +8323,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
- _set_error("Expected integer constant after ','");
+ _set_error(RTR("Expected an integer constant after ','."));
return ERR_PARSE_ERROR;
}
@@ -8077,7 +8336,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
- _set_error("Expected integer constant after ','");
+ _set_error(RTR("Expected an integer constant after ','."));
return ERR_PARSE_ERROR;
}
@@ -8092,44 +8351,44 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')'");
+ _set_expected_error(")");
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.");
+ _set_error(vformat(RTR("Can only specify '%s' once."), "instance_index"));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after 'instance_index'");
+ _set_expected_after_error("(", "instance_index");
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type == TK_OP_SUB) {
- _set_error("The instance index can't be negative.");
+ _set_error(RTR("The instance index can't be negative."));
return ERR_PARSE_ERROR;
}
if (!tk.is_integer_constant()) {
- _set_error("Expected integer constant");
+ _set_error(RTR("Expected an integer constant."));
return ERR_PARSE_ERROR;
}
custom_instance_index = tk.constant;
if (custom_instance_index >= MAX_INSTANCE_UNIFORM_INDICES) {
- _set_error("Allowed instance uniform indices are 0-" + itos(MAX_INSTANCE_UNIFORM_INDICES - 1));
+ _set_error(vformat(RTR("Allowed instance uniform indices must be within [0..%d] range."), MAX_INSTANCE_UNIFORM_INDICES - 1));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')'");
+ _set_expected_error(")");
return ERR_PARSE_ERROR;
}
} else if (tk.type == TK_FILTER_LINEAR) {
@@ -8151,7 +8410,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
- _set_error("This hint is only for sampler types");
+ _set_error(RTR("This hint is only for sampler types."));
return ERR_PARSE_ERROR;
}
@@ -8166,7 +8425,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
uniform2.instance_index = instance_index++;
if (instance_index > MAX_INSTANCE_UNIFORM_INDICES) {
- _set_error("Too many 'instance' uniforms in shader, maximum supported is " + itos(MAX_INSTANCE_UNIFORM_INDICES));
+ _set_error(vformat(RTR("Too many '%s' uniforms in shader, maximum supported is %d."), "instance", MAX_INSTANCE_UNIFORM_INDICES));
return ERR_PARSE_ERROR;
}
}
@@ -8176,7 +8435,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_OP_ASSIGN) {
if (uniform2.array_size > 0) {
- _set_error("Setting default value to a uniform array is not yet supported!");
+ _set_error(RTR("Setting default values to uniform arrays is not supported."));
return ERR_PARSE_ERROR;
}
@@ -8185,7 +8444,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
if (expr->type != Node::TYPE_CONSTANT) {
- _set_error("Expected constant expression after '='");
+ _set_error(RTR("Expected constant expression after '='."));
return ERR_PARSE_ERROR;
}
@@ -8194,7 +8453,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
uniform2.default_value.resize(cn->values.size());
if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) {
- _set_error("Can't convert constant to " + get_datatype_name(uniform2.type));
+ _set_error(vformat(RTR("Can't convert constant to '%s'."), get_datatype_name(uniform2.type)));
return ERR_PARSE_ERROR;
}
tk = _get_token();
@@ -8211,10 +8470,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
+ _set_expected_error(";");
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_GLOBAL_SPACE;
+#endif // DEBUG_ENABLED
completion_type = COMPLETION_NONE;
} else { // varying
ShaderNode::Varying varying;
@@ -8227,37 +8489,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
if (array_size == 0) {
- _set_error("Expected ';' or '['");
+ _set_expected_error(";", "[");
} else {
- _set_error("Expected ';'");
+ _set_expected_error(";");
}
return ERR_PARSE_ERROR;
}
if (tk.type == TK_BRACKET_OPEN) {
- if (array_size > 0) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &varying.array_size, nullptr);
+ if (error != OK) {
+ return error;
}
tk = _get_token();
- if (tk.is_integer_constant() && tk.constant > 0) {
- varying.array_size = (int)tk.constant;
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected integer constant > 0");
- return ERR_PARSE_ERROR;
- }
}
shader->varyings[name] = varying;
@@ -8269,6 +8513,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
} break;
+ case TK_SHADER_TYPE: {
+ _set_error(RTR("Shader type is already defined."));
+ return ERR_PARSE_ERROR;
+ } break;
default: {
//function or constant variable
@@ -8291,20 +8539,27 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (shader->structs.has(tk.text)) {
- if (precision != PRECISION_DEFAULT) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
is_struct = true;
struct_name = tk.text;
} else {
+#ifdef DEBUG_ENABLED
+ if (_lookup_next(next)) {
+ if (next.type == TK_UNIFORM) {
+ keyword_completion_context = CF_UNIFORM_QUALIFIER;
+ }
+ }
+#endif // DEBUG_ENABLED
if (!is_token_datatype(tk.type)) {
- _set_error("Expected constant, function, uniform or varying");
+ _set_error(RTR("Expected constant, function, uniform or varying."));
return ERR_PARSE_ERROR;
}
if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for constants or function return (samplers not allowed)");
+ if (is_constant) {
+ _set_error(RTR("Invalid constant type (samplers are not allowed)."));
+ } else {
+ _set_error(RTR("Invalid function type (samplers are not allowed)."));
+ }
return ERR_PARSE_ERROR;
}
}
@@ -8314,40 +8569,31 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
type = get_token_datatype(tk.type);
}
+
+ if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
prev_pos = _get_tkpos();
tk = _get_token();
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
+
bool unknown_size = false;
+ bool fixed_array_size = false;
if (tk.type == TK_BRACKET_OPEN) {
if (is_constant && RenderingServer::get_singleton()->is_low_end()) {
- _set_error("Global const arrays are only supported on high-end platform!");
+ _set_error(RTR("Global constant arrays are only supported on high-end platforms."));
return ERR_PARSE_ERROR;
}
- bool error = false;
- tk = _get_token();
-
- if (tk.is_integer_constant()) {
- array_size = (int)tk.constant;
- if (array_size > 0) {
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- error = true;
- }
- } else if (tk.type == TK_BRACKET_CLOSE) {
- unknown_size = true;
- } else {
- error = true;
- }
- if (error) {
- _set_error("Expected integer constant > 0 or ']'");
- return ERR_PARSE_ERROR;
+ Error error = _parse_array_size(nullptr, constants, !is_constant, nullptr, &array_size, &unknown_size);
+ if (error != OK) {
+ return error;
}
-
+ fixed_array_size = true;
prev_pos = _get_tkpos();
}
@@ -8357,27 +8603,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (name == StringName()) {
if (is_constant) {
- _set_error("Expected identifier or '[' after datatype.");
+ _set_error(RTR("Expected an identifier or '[' after type."));
} else {
- _set_error("Expected function name after datatype.");
+ _set_error(RTR("Expected a function name after type."));
}
return ERR_PARSE_ERROR;
}
if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_OPEN) {
if (type == TYPE_VOID) {
- _set_error("Expected '(' after function identifier");
+ _set_error(RTR("Expected '(' after function identifier."));
return ERR_PARSE_ERROR;
}
//variable
- bool first = true;
while (true) {
ShaderNode::Constant constant;
constant.name = name;
@@ -8385,46 +8630,30 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.type_str = struct_name;
constant.precision = precision;
constant.initializer = nullptr;
- constant.array_size = (first ? array_size : 0);
- first = false;
+ constant.array_size = array_size;
if (tk.type == TK_BRACKET_OPEN) {
if (RenderingServer::get_singleton()->is_low_end()) {
- _set_error("Global const arrays are only supported on high-end platform!");
+ _set_error(RTR("Global const arrays are only supported on high-end platforms."));
return ERR_PARSE_ERROR;
}
- if (constant.array_size > 0 || unknown_size) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
+ Error error = _parse_array_size(nullptr, constants, false, nullptr, &constant.array_size, &unknown_size);
+ if (error != OK) {
+ return error;
}
tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- unknown_size = true;
- tk = _get_token();
- } else if (tk.is_integer_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 (tk.type == TK_OP_ASSIGN) {
if (!is_constant) {
- _set_error("Expected 'const' keyword before constant definition");
+ _set_error(vformat(RTR("Global non-constant variables are not supported. Expected '%s' keyword before constant definition."), "const"));
return ERR_PARSE_ERROR;
}
if (constant.array_size > 0 || unknown_size) {
bool full_def = false;
- ArrayDeclarationNode::Declaration decl;
+ VariableDeclarationNode::Declaration decl;
decl.name = name;
decl.size = constant.array_size;
@@ -8432,7 +8661,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type != TK_CURLY_BRACKET_OPEN) {
if (unknown_size) {
- _set_error("Expected '{'");
+ _set_expected_error("{");
return ERR_PARSE_ERROR;
}
@@ -8443,7 +8672,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
precision2 = get_token_precision(tk.type);
tk = _get_token();
if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
+ _set_error(RTR("Expected data type after precision modifier."));
return ERR_PARSE_ERROR;
}
}
@@ -8456,83 +8685,60 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
struct_name2 = tk.text;
} else {
if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
+ _set_error(RTR("Invalid data type for the array."));
return ERR_PARSE_ERROR;
}
type2 = get_token_datatype(tk.type);
}
int array_size2 = 0;
-
tk = _get_token();
+
if (tk.type == TK_BRACKET_OPEN) {
- prev_pos = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
+ bool is_unknown_size = false;
+ Error error = _parse_array_size(nullptr, constants, false, nullptr, &array_size2, &is_unknown_size);
+ if (error != OK) {
+ return error;
+ }
+ if (is_unknown_size) {
array_size2 = constant.array_size;
- tk = _get_token();
- } else {
- _set_tkpos(prev_pos);
-
- Node *n = _parse_and_reduce_expression(nullptr, constants);
- 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();
- }
}
+ tk = _get_token();
} else {
- _set_error("Expected '[");
+ _set_expected_error("[");
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 '";
+ String from;
if (type2 == TYPE_STRUCT) {
- error_str += struct_name2;
+ from += struct_name2;
} else {
if (precision2 != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision2);
- error_str += " ";
+ from += get_precision_name(precision2);
+ from += " ";
}
- error_str += get_datatype_name(type2);
+ from += get_datatype_name(type2);
}
- error_str += "[";
- error_str += itos(array_size2);
- error_str += "]'";
- error_str += " to '";
+ from += "[";
+ from += itos(array_size2);
+ from += "]'";
+
+ String to;
if (type == TYPE_STRUCT) {
- error_str += struct_name;
+ to += struct_name;
} else {
if (precision != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision);
- error_str += " ";
+ to += get_precision_name(precision);
+ to += " ";
}
- error_str += get_datatype_name(type);
+ to += get_datatype_name(type);
}
- error_str += "[";
- error_str += itos(constant.array_size);
- error_str += "]'";
- _set_error(error_str);
+ to += "[";
+ to += itos(constant.array_size);
+ to += "]'";
+
+ _set_error(vformat(RTR("Cannot convert from '%s' to '%s'."), from, to));
return ERR_PARSE_ERROR;
}
}
@@ -8541,13 +8747,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (unknown_size) {
if (!curly) {
- _set_error("Expected '{'");
+ _set_expected_error("{");
return ERR_PARSE_ERROR;
}
} else {
if (full_def) {
if (curly) {
- _set_error("Expected '('");
+ _set_expected_error("(");
return ERR_PARSE_ERROR;
}
}
@@ -8560,8 +8766,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression");
+ if (n->type == Node::TYPE_OPERATOR && static_cast<OperatorNode *>(n)->op == OP_CALL) {
+ _set_error(RTR("Expected constant expression."));
return ERR_PARSE_ERROR;
}
@@ -8581,9 +8787,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
break;
} else {
if (curly) {
- _set_error("Expected '}' or ','");
+ _set_expected_error("}", ",");
} else {
- _set_error("Expected ')' or ','");
+ _set_expected_error(")", ",");
}
return ERR_PARSE_ERROR;
}
@@ -8592,11 +8798,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
decl.size = decl.initializer.size();
constant.array_size = decl.initializer.size();
} else if (decl.initializer.size() != constant.array_size) {
- _set_error("Array size mismatch");
+ _set_error(RTR("Array size mismatch."));
return ERR_PARSE_ERROR;
}
}
+ array_size = constant.array_size;
+
ConstantNode *expr = memnew(ConstantNode);
expr->datatype = constant.type;
@@ -8609,16 +8817,27 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
} else {
+#ifdef DEBUG_ENABLED
+ if (constant.type == DataType::TYPE_BOOL) {
+ keyword_completion_context = CF_BOOLEAN;
+ }
+#endif // DEBUG_ENABLED
+
//variable created with assignment! must parse an expression
Node *expr = _parse_and_reduce_expression(nullptr, constants);
if (!expr) {
return ERR_PARSE_ERROR;
}
- if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
- OperatorNode *op = ((OperatorNode *)expr);
+#ifdef DEBUG_ENABLED
+ if (constant.type == DataType::TYPE_BOOL) {
+ keyword_completion_context = CF_GLOBAL_SPACE;
+ }
+#endif // DEBUG_ENABLED
+ if (expr->type == Node::TYPE_OPERATOR && static_cast<OperatorNode *>(expr)->op == OP_CALL) {
+ OperatorNode *op = static_cast<OperatorNode *>(expr);
for (int i = 1; i < op->arguments.size(); i++) {
if (!_check_node_constness(op->arguments[i])) {
- _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ _set_error(vformat(RTR("Expected constant expression for argument %d of function call after '='."), i - 1));
return ERR_PARSE_ERROR;
}
}
@@ -8633,10 +8852,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
} else {
if (constant.array_size > 0 || unknown_size) {
- _set_error("Expected array initialization");
+ _set_error(RTR("Expected array initialization."));
return ERR_PARSE_ERROR;
} else {
- _set_error("Expected initialization of constant");
+ _set_error(RTR("Expected initialization of constant."));
return ERR_PARSE_ERROR;
}
}
@@ -8652,27 +8871,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_COMMA) {
tk = _get_token();
if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after type");
+ _set_error(RTR("Expected an identifier after type."));
return ERR_PARSE_ERROR;
}
name = tk.text;
if (_find_identifier(nullptr, false, constants, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
if (has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
+ _set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
tk = _get_token();
+ if (!fixed_array_size) {
+ array_size = 0;
+ }
+ unknown_size = false;
+
} else if (tk.type == TK_SEMICOLON) {
break;
} else {
- _set_error("Expected ',' or ';' after constant");
+ _set_expected_error(",", ";");
return ERR_PARSE_ERROR;
}
}
@@ -8697,6 +8921,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
}
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (!shader->functions[i].callable && shader->functions[i].name == name) {
+ _set_redefinition_error(String(name));
+ return ERR_PARSE_ERROR;
+ }
+ }
+
ShaderNode::Function function;
function.callable = !p_functions.has(name);
@@ -8733,45 +8964,116 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_CONST_KEYWORD | CF_FUNC_DECL_PARAM_SPEC | CF_PRECISION_MODIFIER | CF_FUNC_DECL_PARAM_TYPE; // eg. const in mediump float
+
+ if (_lookup_next(next)) {
+ if (next.type == TK_CONST) {
+ keyword_completion_context = CF_UNSPECIFIED;
+ } else if (is_token_arg_qual(next.type)) {
+ keyword_completion_context = CF_CONST_KEYWORD;
+ } else if (is_token_precision(next.type)) {
+ keyword_completion_context = (CF_CONST_KEYWORD | CF_FUNC_DECL_PARAM_SPEC | CF_FUNC_DECL_PARAM_TYPE);
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context = (CF_CONST_KEYWORD | CF_FUNC_DECL_PARAM_SPEC | CF_PRECISION_MODIFIER);
+ }
+ }
+#endif // DEBUG_ENABLED
- bool is_const = false;
+ bool param_is_const = false;
if (tk.type == TK_CONST) {
- is_const = true;
+ param_is_const = true;
tk = _get_token();
- }
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & CF_CONST_KEYWORD) {
+ keyword_completion_context ^= CF_CONST_KEYWORD;
+ }
- ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
+ if (_lookup_next(next)) {
+ if (is_token_arg_qual(next.type)) {
+ keyword_completion_context = CF_UNSPECIFIED;
+ } else if (is_token_precision(next.type)) {
+ keyword_completion_context = (CF_FUNC_DECL_PARAM_SPEC | CF_FUNC_DECL_PARAM_TYPE);
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context = (CF_FUNC_DECL_PARAM_SPEC | CF_PRECISION_MODIFIER);
+ }
+ }
+#endif // DEBUG_ENABLED
+ }
- 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;
+ ArgumentQualifier param_qualifier = ARGUMENT_QUALIFIER_IN;
+ if (is_token_arg_qual(tk.type)) {
+ bool error = false;
+ switch (tk.type) {
+ case TK_ARG_IN: {
+ param_qualifier = ARGUMENT_QUALIFIER_IN;
+ } break;
+ case TK_ARG_OUT: {
+ if (param_is_const) {
+ _set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const"));
+ error = true;
+ }
+ param_qualifier = ARGUMENT_QUALIFIER_OUT;
+ } break;
+ case TK_ARG_INOUT: {
+ if (param_is_const) {
+ _set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const"));
+ error = true;
+ }
+ param_qualifier = ARGUMENT_QUALIFIER_INOUT;
+ } break;
+ default:
+ error = true;
+ break;
}
- 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'.");
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & CF_CONST_KEYWORD) {
+ keyword_completion_context ^= CF_CONST_KEYWORD;
+ }
+ if (keyword_completion_context & CF_FUNC_DECL_PARAM_SPEC) {
+ keyword_completion_context ^= CF_FUNC_DECL_PARAM_SPEC;
+ }
+
+ if (_lookup_next(next)) {
+ if (is_token_precision(next.type)) {
+ keyword_completion_context = CF_FUNC_DECL_PARAM_TYPE;
+ } else if (is_token_datatype(next.type)) {
+ keyword_completion_context = CF_PRECISION_MODIFIER;
+ }
+ }
+#endif // DEBUG_ENABLED
+ if (error) {
return ERR_PARSE_ERROR;
}
- qualifier = ARGUMENT_QUALIFIER_INOUT;
- tk = _get_token();
}
- DataType ptype;
- StringName pname;
+ DataType param_type;
+ StringName param_name;
StringName param_struct_name;
- DataPrecision pprecision = PRECISION_DEFAULT;
- bool use_precision = false;
+ DataPrecision param_precision = PRECISION_DEFAULT;
int arg_array_size = 0;
if (is_token_precision(tk.type)) {
- pprecision = get_token_precision(tk.type);
+ param_precision = get_token_precision(tk.type);
tk = _get_token();
- use_precision = true;
+#ifdef DEBUG_ENABLED
+ if (keyword_completion_context & CF_CONST_KEYWORD) {
+ keyword_completion_context ^= CF_CONST_KEYWORD;
+ }
+ if (keyword_completion_context & CF_FUNC_DECL_PARAM_SPEC) {
+ keyword_completion_context ^= CF_FUNC_DECL_PARAM_SPEC;
+ }
+ if (keyword_completion_context & CF_PRECISION_MODIFIER) {
+ keyword_completion_context ^= CF_PRECISION_MODIFIER;
+ }
+
+ if (_lookup_next(next)) {
+ if (is_token_datatype(next.type)) {
+ keyword_completion_context = CF_UNSPECIFIED;
+ }
+ }
+#endif // DEBUG_ENABLED
}
is_struct = false;
@@ -8784,124 +9086,85 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
used_structs[param_struct_name].used = true;
}
#endif // DEBUG_ENABLED
- if (use_precision) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
}
if (!is_struct && !is_token_datatype(tk.type)) {
- _set_error("Expected a valid datatype for argument");
+ _set_error(RTR("Expected a valid data type for argument."));
return ERR_PARSE_ERROR;
}
- if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
+ if (param_qualifier == ARGUMENT_QUALIFIER_OUT || param_qualifier == ARGUMENT_QUALIFIER_INOUT) {
if (is_sampler_type(get_token_datatype(tk.type))) {
- _set_error("Opaque types cannot be output parameters.");
+ _set_error(RTR("Opaque types cannot be output parameters."));
return ERR_PARSE_ERROR;
}
}
if (is_struct) {
- ptype = TYPE_STRUCT;
+ param_type = TYPE_STRUCT;
} else {
- ptype = get_token_datatype(tk.type);
- if (_validate_datatype(ptype) != OK) {
+ param_type = get_token_datatype(tk.type);
+ if (_validate_datatype(param_type) != OK) {
return ERR_PARSE_ERROR;
}
- if (ptype == TYPE_VOID) {
- _set_error("void not allowed in argument");
+ if (param_type == TYPE_VOID) {
+ _set_error(RTR("Void type not allowed as argument."));
return ERR_PARSE_ERROR;
}
}
+ if (param_precision != PRECISION_DEFAULT && _validate_precision(param_type, param_precision) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_UNSPECIFIED;
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- bool error = false;
- tk = _get_token();
-
- if (tk.is_integer_constant()) {
- arg_array_size = (int)tk.constant;
-
- if (arg_array_size > 0) {
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- error = true;
- }
- } else {
- error = true;
- }
- if (error) {
- _set_error("Expected integer constant > 0");
- return ERR_PARSE_ERROR;
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &arg_array_size, nullptr);
+ if (error != OK) {
+ return error;
}
tk = _get_token();
}
if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier for argument name");
+ _set_error(RTR("Expected an identifier for argument name."));
return ERR_PARSE_ERROR;
}
- pname = tk.text;
+ param_name = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(func_node->body, false, builtins, param_name, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
- _set_error("Redefinition of '" + String(pname) + "'");
+ _set_redefinition_error(String(param_name));
return ERR_PARSE_ERROR;
}
}
- if (has_builtin(p_functions, pname)) {
- _set_error("Redefinition of '" + String(pname) + "'");
+ if (has_builtin(p_functions, param_name)) {
+ _set_redefinition_error(String(param_name));
return ERR_PARSE_ERROR;
}
FunctionNode::Argument arg;
- arg.type = ptype;
- arg.name = pname;
+ arg.type = param_type;
+ arg.name = param_name;
arg.type_str = param_struct_name;
- arg.precision = pprecision;
- arg.qualifier = qualifier;
+ arg.precision = param_precision;
+ arg.qualifier = param_qualifier;
arg.tex_argument_check = false;
arg.tex_builtin_check = false;
arg.tex_argument_filter = FILTER_DEFAULT;
arg.tex_argument_repeat = REPEAT_DEFAULT;
- arg.is_const = is_const;
+ arg.is_const = param_is_const;
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- if (arg_array_size > 0) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
- }
- bool error = false;
- tk = _get_token();
-
- if (tk.is_integer_constant()) {
- arg_array_size = (int)tk.constant;
-
- if (arg_array_size > 0) {
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- error = true;
- }
- } else {
- error = true;
- }
-
- if (error) {
- _set_error("Expected integer constant > 0");
- return ERR_PARSE_ERROR;
+ Error error = _parse_array_size(nullptr, constants, true, nullptr, &arg_array_size, nullptr);
+ if (error != OK) {
+ return error;
}
tk = _get_token();
}
@@ -8913,7 +9176,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
//do none and go on
} else if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ',' or ')' after identifier");
+ _set_expected_error(",", ")");
return ERR_PARSE_ERROR;
}
}
@@ -8921,11 +9184,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (p_functions.has(name)) {
//if one of the core functions, make sure they are of the correct form
if (func_node->arguments.size() > 0) {
- _set_error("Function '" + String(name) + "' expects no arguments.");
+ _set_error(vformat(RTR("Function '%s' expects no arguments."), String(name)));
return ERR_PARSE_ERROR;
}
if (func_node->return_type != TYPE_VOID) {
- _set_error("Function '" + String(name) + "' must be of void return type.");
+ _set_error(vformat(RTR("Function '%s' must be of '%s' return type."), String(name), "void"));
return ERR_PARSE_ERROR;
}
}
@@ -8933,21 +9196,26 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//all good let's parse inside the function!
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{' to begin function");
+ _set_error(RTR("Expected a '{' to begin function."));
return ERR_PARSE_ERROR;
}
current_function = name;
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_BLOCK;
+#endif // DEBUG_ENABLED
Error err = _parse_block(func_node->body, builtins);
if (err) {
return err;
}
-
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_GLOBAL_SPACE;
+#endif // DEBUG_ENABLED
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.");
+ _set_error(vformat(RTR("Expected at least one '%s' statement in a non-void function."), "return"));
return ERR_PARSE_ERROR;
}
}
@@ -8958,14 +9226,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
}
- int error_line;
- String error_message;
- if (!_check_varying_usages(&error_line, &error_message)) {
- _set_tkpos({ 0, error_line });
- _set_error(error_message);
- return ERR_PARSE_ERROR;
+#ifdef DEBUG_ENABLED
+ if (check_device_limit_warnings && uniform_buffer_exceeded_line != -1) {
+ _add_warning(ShaderWarning::DEVICE_LIMIT_EXCEEDED, uniform_buffer_exceeded_line, RTR("uniform buffer"), { uniform_buffer_size, max_uniform_buffer_size });
}
-
+#endif // DEBUG_ENABLED
return OK;
}
@@ -8984,7 +9249,7 @@ Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOper
for (int i = p_flow->blocks.size() - 1; i >= 0; i--) {
if (p_flow->blocks[i]->type == Node::TYPE_BLOCK) {
- BlockNode *last_block = (BlockNode *)p_flow->blocks[i];
+ BlockNode *last_block = static_cast<BlockNode *>(p_flow->blocks[i]);
if (_find_last_flow_op_in_block(last_block, p_op) == OK) {
found = true;
break;
@@ -9002,7 +9267,7 @@ Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperat
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];
+ ControlFlowNode *flow = static_cast<ControlFlowNode *>(p_block->statements[i]);
if (flow->flow_op == p_op) {
found = true;
break;
@@ -9013,7 +9278,7 @@ Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperat
}
}
} else if (p_block->statements[i]->type == Node::TYPE_BLOCK) {
- BlockNode *block = (BlockNode *)p_block->statements[i];
+ BlockNode *block = static_cast<BlockNode *>(p_block->statements[i]);
if (_find_last_flow_op_in_block(block, p_op) == OK) {
found = true;
break;
@@ -9169,7 +9434,7 @@ Error ShaderLanguage::compile(const String &p_code, const ShaderCompileInfo &p_i
return OK;
}
-Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_info, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
+Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_info, List<ScriptLanguage::CodeCompletionOption> *r_options, String &r_call_hint) {
clear();
code = p_code;
@@ -9181,11 +9446,40 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
shader = alloc_node<ShaderNode>();
_parse_shader(p_info.functions, p_info.render_modes, p_info.shader_types);
+#ifdef DEBUG_ENABLED
+ // Adds context keywords.
+ if (keyword_completion_context != CF_UNSPECIFIED) {
+ int sz = sizeof(keyword_list) / sizeof(KeyWord);
+ for (int i = 0; i < sz; i++) {
+ if (keyword_list[i].flags == CF_UNSPECIFIED) {
+ break; // Ignore hint keywords (parsed below).
+ }
+ if (keyword_list[i].flags & keyword_completion_context) {
+ if (keyword_list[i].excluded_shader_types.has(shader_type_identifier)) {
+ continue;
+ }
+ if (!keyword_list[i].functions.is_empty() && !keyword_list[i].functions.has(current_function)) {
+ continue;
+ }
+ ScriptLanguage::CodeCompletionOption option(keyword_list[i].text, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ r_options->push_back(option);
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
+
switch (completion_type) {
case COMPLETION_NONE: {
//do nothing
return OK;
} break;
+ case COMPLETION_SHADER_TYPE: {
+ for (const String &shader_type : p_info.shader_types) {
+ ScriptLanguage::CodeCompletionOption option(shader_type, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ r_options->push_back(option);
+ }
+ return OK;
+ } break;
case COMPLETION_RENDER_MODE: {
for (int i = 0; i < p_info.render_modes.size(); i++) {
const ModeInfo &info = p_info.render_modes[i];
@@ -9201,7 +9495,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (!found) {
for (int j = 0; j < info.options.size(); j++) {
- ScriptCodeCompletionOption option(String(info.name) + "_" + String(info.options[j]), ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(String(info.name) + "_" + String(info.options[j]), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_options->push_back(option);
}
}
@@ -9209,7 +9503,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
const String name = String(info.name);
if (!shader->render_modes.has(name)) {
- ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_options->push_back(option);
}
}
@@ -9221,7 +9515,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (shader->structs.has(completion_struct)) {
StructNode *node = shader->structs[completion_struct].shader_struct;
for (int i = 0; i < node->members.size(); i++) {
- ScriptCodeCompletionOption option(node->members[i]->name, ScriptCodeCompletionOption::KIND_MEMBER);
+ ScriptLanguage::CodeCompletionOption option(node->members[i]->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
r_options->push_back(option);
}
}
@@ -9230,7 +9524,20 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
} break;
case COMPLETION_MAIN_FUNCTION: {
for (const KeyValue<StringName, FunctionInfo> &E : p_info.functions) {
- ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION);
+ if (!E.value.main_function) {
+ continue;
+ }
+ bool found = false;
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (shader->functions[i].name == E.key) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ continue;
+ }
+ ScriptLanguage::CodeCompletionOption option(E.key, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
r_options->push_back(option);
}
@@ -9239,7 +9546,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
case COMPLETION_IDENTIFIER:
case COMPLETION_FUNCTION_CALL: {
bool comp_ident = completion_type == COMPLETION_IDENTIFIER;
- Map<String, ScriptCodeCompletionOption::Kind> matches;
+ Map<String, ScriptLanguage::CodeCompletionKind> matches;
StringName skip_function;
BlockNode *block = completion_block;
@@ -9248,7 +9555,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (comp_ident) {
for (const KeyValue<StringName, BlockNode::Variable> &E : block->variables) {
if (E.value.line < completion_line) {
- matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE);
+ matches.insert(E.key, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE);
}
}
}
@@ -9256,7 +9563,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (block->parent_function) {
if (comp_ident) {
for (int i = 0; i < block->parent_function->arguments.size(); i++) {
- matches.insert(block->parent_function->arguments[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ matches.insert(block->parent_function->arguments[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE);
}
}
skip_function = block->parent_function->name;
@@ -9267,9 +9574,9 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (comp_ident) {
if (p_info.functions.has("global")) {
for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions["global"].built_ins) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
+ ScriptLanguage::CodeCompletionKind kind = ScriptLanguage::CODE_COMPLETION_KIND_MEMBER;
if (E.value.constant) {
- kind = ScriptCodeCompletionOption::KIND_CONSTANT;
+ kind = ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT;
}
matches.insert(E.key, kind);
}
@@ -9277,9 +9584,9 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (p_info.functions.has("constants")) {
for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions["constants"].built_ins) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
+ ScriptLanguage::CodeCompletionKind kind = ScriptLanguage::CODE_COMPLETION_KIND_MEMBER;
if (E.value.constant) {
- kind = ScriptCodeCompletionOption::KIND_CONSTANT;
+ kind = ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT;
}
matches.insert(E.key, kind);
}
@@ -9287,19 +9594,22 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (skip_function != StringName() && p_info.functions.has(skip_function)) {
for (const KeyValue<StringName, BuiltInInfo> &E : p_info.functions[skip_function].built_ins) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
+ ScriptLanguage::CodeCompletionKind kind = ScriptLanguage::CODE_COMPLETION_KIND_MEMBER;
if (E.value.constant) {
- kind = ScriptCodeCompletionOption::KIND_CONSTANT;
+ kind = ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT;
}
matches.insert(E.key, kind);
}
}
+ for (const KeyValue<StringName, ShaderNode::Constant> &E : shader->constants) {
+ matches.insert(E.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ }
for (const KeyValue<StringName, ShaderNode::Varying> &E : shader->varyings) {
- matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE);
+ matches.insert(E.key, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE);
}
for (const KeyValue<StringName, ShaderNode::Uniform> &E : shader->uniforms) {
- matches.insert(E.key, ScriptCodeCompletionOption::KIND_MEMBER);
+ matches.insert(E.key, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
}
}
@@ -9307,7 +9617,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (!shader->functions[i].callable || shader->functions[i].name == skip_function) {
continue;
}
- matches.insert(String(shader->functions[i].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ matches.insert(String(shader->functions[i].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
}
int idx = 0;
@@ -9315,7 +9625,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (stages && stages->has(skip_function)) {
for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) {
- matches.insert(String(E.key), ScriptCodeCompletionOption::KIND_FUNCTION);
+ matches.insert(String(E.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
}
}
@@ -9324,7 +9634,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
idx++;
continue;
}
- matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ matches.insert(String(builtin_func_defs[idx].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
idx++;
}
@@ -9338,15 +9648,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
continue;
}
if (builtin_func_defs[idx].tag == completion_class) {
- matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ matches.insert(String(builtin_func_defs[idx].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
}
idx++;
}
}
- for (const KeyValue<String, ScriptCodeCompletionOption::Kind> &E : matches) {
- ScriptCodeCompletionOption option(E.key, E.value);
- if (E.value == ScriptCodeCompletionOption::KIND_FUNCTION) {
+ for (const KeyValue<String, ScriptLanguage::CodeCompletionKind> &E : matches) {
+ ScriptLanguage::CodeCompletionOption option(E.key, E.value);
+ if (E.value == ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION) {
option.insert_text += "(";
}
r_options->push_back(option);
@@ -9595,18 +9905,18 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
for (int i = 0; i < limit; i++) {
- r_options->push_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
- r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
- r_options->push_back(ScriptCodeCompletionOption(String::chr(coordt[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
+ r_options->push_back(ScriptLanguage::CodeCompletionOption(String::chr(colv[i]), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT));
+ r_options->push_back(ScriptLanguage::CodeCompletionOption(String::chr(coordv[i]), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT));
+ r_options->push_back(ScriptLanguage::CodeCompletionOption(String::chr(coordt[i]), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT));
}
} break;
case COMPLETION_HINT: {
- if (completion_base == DataType::TYPE_VEC4) {
- ScriptCodeCompletionOption option("hint_color", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ if (completion_base == DataType::TYPE_VEC3 || completion_base == DataType::TYPE_VEC4) {
+ ScriptLanguage::CodeCompletionOption option("hint_color", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_options->push_back(option);
} else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT) && !completion_base_array) {
- ScriptCodeCompletionOption option("hint_range", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option("hint_range", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
if (completion_base == DataType::TYPE_INT) {
option.insert_text = "hint_range(0, 100, 1)";
@@ -9642,12 +9952,12 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
for (int i = 0; i < options.size(); i++) {
- ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option(options[i], ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
r_options->push_back(option);
}
}
if (!completion_base_array) {
- ScriptCodeCompletionOption option("instance_index", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption option("instance_index", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
option.insert_text = "instance_index(0)";
r_options->push_back(option);
}
@@ -9673,7 +9983,7 @@ ShaderLanguage::ShaderLanguage() {
nodes = nullptr;
completion_class = TAG_GLOBAL;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions);
warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);