summaryrefslogtreecommitdiff
path: root/servers/visual/shader_language.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/visual/shader_language.cpp')
-rw-r--r--servers/visual/shader_language.cpp283
1 files changed, 252 insertions, 31 deletions
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index fd1eb77143..ca50d0d049 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -123,6 +123,12 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"TYPE_SAMPLER2D",
"TYPE_ISAMPLER2D",
"TYPE_USAMPLER2D",
+ "TYPE_SAMPLER2DARRAY",
+ "TYPE_ISAMPLER2DARRAY",
+ "TYPE_USAMPLER2DARRAY",
+ "TYPE_SAMPLER3D",
+ "TYPE_ISAMPLER3D",
+ "TYPE_USAMPLER3D",
"TYPE_SAMPLERCUBE",
"INTERPOLATION_FLAT",
"INTERPOLATION_NO_PERSPECTIVE",
@@ -257,6 +263,12 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ 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_INTERPOLATION_FLAT, "flat" },
{ TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" },
@@ -516,13 +528,14 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
bool hexa_found = false;
bool sign_found = false;
bool minus_exponent_found = false;
+ bool float_suffix_found = false;
String str;
int i = 0;
while (true) {
if (GETCHAR(i) == '.') {
- if (period_found || exponent_found)
+ if (period_found || exponent_found || hexa_found || float_suffix_found)
return _make_token(TK_ERROR, "Invalid numeric constant");
period_found = true;
} else if (GETCHAR(i) == 'x') {
@@ -530,11 +543,16 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_ERROR, "Invalid numeric constant");
hexa_found = true;
} else if (GETCHAR(i) == 'e') {
- if (hexa_found || exponent_found)
+ if (hexa_found || exponent_found || float_suffix_found)
return _make_token(TK_ERROR, "Invalid numeric constant");
exponent_found = true;
+ } else if (GETCHAR(i) == 'f') {
+ if (hexa_found || exponent_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ float_suffix_found = true;
} else if (_is_number(GETCHAR(i))) {
- //all ok
+ if (float_suffix_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
} else if (hexa_found && _is_hex(GETCHAR(i))) {
} else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
@@ -550,21 +568,60 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
i++;
}
- if (!_is_number(str[str.length() - 1]))
- return _make_token(TK_ERROR, "Invalid numeric constant");
+ CharType last_char = str[str.length() - 1];
+
+ if (hexa_found) {
+ //hex integers eg."0xFF" or "0x12AB", etc - NOT supported yet
+ return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant - Not supported");
+ } else if (period_found || float_suffix_found) {
+ //floats
+ if (period_found) {
+ if (float_suffix_found) {
+ //checks for eg "1.f" or "1.99f" notations
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //checks for eg. "1." or "1.99" notations
+ if (last_char != '.' && !_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+ } else if (float_suffix_found) {
+ // if no period found the float suffix must be the last character, like in "2f" for "2.0"
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+
+ if (float_suffix_found) {
+ //strip the suffix
+ str = str.left(str.length() - 1);
+ //compensate reading cursor position
+ char_idx += 1;
+ }
+
+ if (!str.is_valid_float()) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //integers
+ if (!_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
+ }
+ if (!str.is_valid_integer()) {
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ }
+ }
char_idx += str.length();
Token tk;
- if (period_found || minus_exponent_found)
+ if (period_found || minus_exponent_found || float_suffix_found)
tk.type = TK_REAL_CONSTANT;
else
tk.type = TK_INT_CONSTANT;
- if (!str.is_valid_float()) {
- return _make_token(TK_ERROR, "Invalid numeric constant");
- }
-
- tk.constant = str.to_double();
+ tk.constant = str.to_double(); //wont work with hex
tk.line = tk_line;
return tk;
@@ -612,6 +669,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
}
ERR_PRINT("BUG");
return Token();
+
+#undef GETCHAR
}
String ShaderLanguage::token_debug(const String &p_code) {
@@ -658,6 +717,12 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) {
p_type == TK_TYPE_SAMPLER2D ||
p_type == TK_TYPE_ISAMPLER2D ||
p_type == TK_TYPE_USAMPLER2D ||
+ p_type == TK_TYPE_SAMPLER2DARRAY ||
+ p_type == TK_TYPE_ISAMPLER2DARRAY ||
+ p_type == TK_TYPE_USAMPLER2DARRAY ||
+ p_type == TK_TYPE_SAMPLER3D ||
+ p_type == TK_TYPE_ISAMPLER3D ||
+ p_type == TK_TYPE_USAMPLER3D ||
p_type == TK_TYPE_SAMPLERCUBE);
}
@@ -729,6 +794,12 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
case TYPE_SAMPLER2D: return "sampler2D";
case TYPE_ISAMPLER2D: return "isampler2D";
case TYPE_USAMPLER2D: return "usampler2D";
+ case TYPE_SAMPLER2DARRAY: return "sampler2DArray";
+ case TYPE_ISAMPLER2DARRAY: return "isampler2DArray";
+ case TYPE_USAMPLER2DARRAY: return "usampler2DArray";
+ case TYPE_SAMPLER3D: return "sampler3D";
+ case TYPE_ISAMPLER3D: return "isampler3D";
+ case TYPE_USAMPLER3D: return "usampler3D";
case TYPE_SAMPLERCUBE: return "samplerCube";
}
@@ -1376,6 +1447,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID } },
{ "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID } },
+ //conversion between matrixes
+
+ { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID } },
+ { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID } },
+ { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID } },
+ { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID } },
+ { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID } },
+ { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID } },
+
//builtins - trigonometry
{ "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } },
@@ -1791,6 +1871,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } },
{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID } },
@@ -1802,6 +1888,24 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID } },
{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID } },
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
@@ -1820,15 +1924,38 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
{ "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
{ "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
{ "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+
{ "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
@@ -1841,6 +1968,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
{ "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
{ "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
{ "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } },
@@ -2128,7 +2261,16 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) {
bool ShaderLanguage::is_sampler_type(DataType p_type) {
- return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || p_type == TYPE_USAMPLER2D || p_type == TYPE_SAMPLERCUBE;
+ return p_type == TYPE_SAMPLER2D ||
+ p_type == TYPE_ISAMPLER2D ||
+ p_type == TYPE_USAMPLER2D ||
+ p_type == TYPE_SAMPLER2DARRAY ||
+ p_type == TYPE_ISAMPLER2DARRAY ||
+ p_type == TYPE_USAMPLER2DARRAY ||
+ p_type == TYPE_SAMPLER3D ||
+ p_type == TYPE_ISAMPLER3D ||
+ p_type == TYPE_USAMPLER3D ||
+ p_type == TYPE_SAMPLERCUBE;
}
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
@@ -2295,24 +2437,54 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
return false;
}
-bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types) {
+bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
+
if (op->op == OP_INDEX) {
- return _validate_assign(op->arguments[0], p_builtin_types);
+ return _validate_assign(op->arguments[0], p_builtin_types, r_message);
+
+ } else if (_is_operator_assign(op->op)) {
+ //chained assignment
+ return _validate_assign(op->arguments[1], p_builtin_types, r_message);
+
+ } else if (op->op == OP_CALL) {
+ if (r_message)
+ *r_message = RTR("Assignment to function.");
+ return false;
}
- }
- if (p_node->type == Node::TYPE_VARIABLE) {
+ } else if (p_node->type == Node::TYPE_MEMBER) {
+
+ MemberNode *member = static_cast<MemberNode *>(p_node);
+ return _validate_assign(member->owner, p_builtin_types, r_message);
+
+ } else if (p_node->type == Node::TYPE_VARIABLE) {
VariableNode *var = static_cast<VariableNode *>(p_node);
- if (p_builtin_types.has(var->name) && p_builtin_types[var->name].constant) {
- return false; //ops not valid
+
+ if (shader->uniforms.has(var->name)) {
+ if (r_message)
+ *r_message = RTR("Assignment to uniform.");
+ return false;
+ }
+
+ if (shader->varyings.has(var->name) && current_function != String("vertex")) {
+ if (r_message)
+ *r_message = RTR("Varyings can only be assigned in vertex function.");
+ return false;
+ }
+
+ if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) {
+ return true;
}
}
- return true;
+
+ if (r_message)
+ *r_message = "Assignment to constant expression.";
+ return false;
}
ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
@@ -2460,7 +2632,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//add to current function as dependency
for (int j = 0; j < shader->functions.size(); j++) {
if (shader->functions[j].name == current_function) {
- shader->functions[j].uses_function.insert(name);
+ shader->functions.write[j].uses_function.insert(name);
break;
}
}
@@ -3010,8 +3182,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
op->arguments.push_back(expression[i + 1].node);
- expression[i].is_op = false;
- expression[i].node = op;
+ expression.write[i].is_op = false;
+ expression.write[i].node = op;
if (!_validate_operator(op, &op->return_cache)) {
@@ -3045,8 +3217,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->arguments.push_back(expression[next_op + 1].node);
op->arguments.push_back(expression[next_op + 3].node);
- expression[next_op - 1].is_op = false;
- expression[next_op - 1].node = op;
+ expression.write[next_op - 1].is_op = false;
+ expression.write[next_op - 1].node = op;
if (!_validate_operator(op, &op->return_cache)) {
String at;
@@ -3079,10 +3251,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_V(NULL);
}
- if (_is_operator_assign(op->op) && !_validate_assign(expression[next_op - 1].node, p_builtin_types)) {
+ if (_is_operator_assign(op->op)) {
- _set_error("Assignment to constant expression.");
- return NULL;
+ String assign_message;
+ if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) {
+
+ _set_error(assign_message);
+ return NULL;
+ }
}
if (expression[next_op + 1].is_op) {
@@ -3096,7 +3272,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->arguments.push_back(expression[next_op - 1].node); //expression goes as left
op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right
- expression[next_op - 1].node = op;
+ expression.write[next_op - 1].node = op;
//replace all 3 nodes by this operator and make it an expression
@@ -3138,7 +3314,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
for (int i = 1; i < op->arguments.size(); i++) {
- op->arguments[i] = _reduce_expression(p_block, op->arguments[i]);
+ op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]);
if (op->arguments[i]->type == Node::TYPE_CONSTANT) {
ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]);
@@ -3178,7 +3354,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
return cn;
} else if (op->op == OP_NEGATE) {
- op->arguments[0] = _reduce_expression(p_block, op->arguments[0]);
+ op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]);
if (op->arguments[0]->type == Node::TYPE_CONSTANT) {
ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]);
@@ -4064,13 +4240,58 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return OK;
}
+// skips over whitespace and /* */ and // comments
+static int _get_first_ident_pos(const String &p_code) {
+
+ int idx = 0;
+
+#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0))
+
+ while (true) {
+ if (GETCHAR(0) == '/' && GETCHAR(1) == '/') {
+ idx += 2;
+ while (true) {
+ if (GETCHAR(0) == 0) return 0;
+ if (GETCHAR(0) == '\n') {
+ idx++;
+ break; // loop
+ }
+ idx++;
+ }
+ } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') {
+ idx += 2;
+ while (true) {
+ if (GETCHAR(0) == 0) return 0;
+ if (GETCHAR(0) == '*' && GETCHAR(1) == '/') {
+ idx += 2;
+ break; // loop
+ }
+ idx++;
+ }
+ } else {
+ switch (GETCHAR(0)) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n': {
+ idx++;
+ } break; // switch
+ default:
+ return idx;
+ }
+ }
+ }
+
+#undef GETCHAR
+}
+
String ShaderLanguage::get_shader_type(const String &p_code) {
bool reading_type = false;
String cur_identifier;
- for (int i = 0; i < p_code.length(); i++) {
+ for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) {
if (p_code[i] == ';') {
break;