Browse Source

Fix shader incorrectly expects `int` on `uint` and vice-versa in cases

Chaosus 1 year ago
parent
commit
b2611c198e
2 changed files with 71 additions and 55 deletions
  1. 68 55
      servers/rendering/shader_language.cpp
  2. 3 0
      servers/rendering/shader_language.h

+ 68 - 55
servers/rendering/shader_language.cpp

@@ -8071,12 +8071,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 			if (!n) {
 			if (!n) {
 				return ERR_PARSE_ERROR;
 				return ERR_PARSE_ERROR;
 			}
 			}
-			{
-				const ShaderLanguage::DataType switch_type = n->get_datatype();
-				if (switch_type != TYPE_INT && switch_type != TYPE_UINT) {
-					_set_error(RTR("Expected an integer expression."));
-					return ERR_PARSE_ERROR;
-				}
+			const ShaderLanguage::DataType data_type = n->get_datatype();
+			if (data_type != TYPE_INT && data_type != TYPE_UINT) {
+				_set_error(RTR("Expected an integer or unsigned integer expression."));
+				return ERR_PARSE_ERROR;
 			}
 			}
 			tk = _get_token();
 			tk = _get_token();
 			if (tk.type != TK_PARENTHESIS_CLOSE) {
 			if (tk.type != TK_PARENTHESIS_CLOSE) {
@@ -8091,11 +8089,22 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 			BlockNode *switch_block = alloc_node<BlockNode>();
 			BlockNode *switch_block = alloc_node<BlockNode>();
 			switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH;
 			switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH;
 			switch_block->parent_block = p_block;
 			switch_block->parent_block = p_block;
+			switch_block->expected_type = data_type;
 			cf->expressions.push_back(n);
 			cf->expressions.push_back(n);
 			cf->blocks.push_back(switch_block);
 			cf->blocks.push_back(switch_block);
 			p_block->statements.push_back(cf);
 			p_block->statements.push_back(cf);
 
 
-			int prev_type = TK_CF_CASE;
+			pos = _get_tkpos();
+			tk = _get_token();
+			TokenType prev_type;
+			if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) {
+				prev_type = tk.type;
+				_set_tkpos(pos);
+			} else {
+				_set_expected_error("case", "default");
+				return ERR_PARSE_ERROR;
+			}
+
 			while (true) { // Go-through multiple cases.
 			while (true) { // Go-through multiple cases.
 
 
 				if (_parse_block(switch_block, p_function_info, true, true, false) != OK) {
 				if (_parse_block(switch_block, p_function_info, true, true, false) != OK) {
@@ -8117,43 +8126,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 					_set_tkpos(pos);
 					_set_tkpos(pos);
 					continue;
 					continue;
 				} else {
 				} else {
-					HashSet<int> constants;
-					for (ShaderLanguage::Node *statement : switch_block->statements) { // Checks for duplicates.
-						ControlFlowNode *flow = static_cast<ControlFlowNode *>(statement);
-						if (flow) {
-							if (flow->flow_op == FLOW_OP_CASE) {
-								if (flow->expressions[0]->type == Node::NODE_TYPE_CONSTANT) {
-									ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]);
-									if (!cn || cn->values.is_empty()) {
-										return ERR_PARSE_ERROR;
-									}
-									if (constants.has(cn->values[0].sint)) {
-										_set_error(vformat(RTR("Duplicated case label: %d."), cn->values[0].sint));
-										return ERR_PARSE_ERROR;
-									}
-									constants.insert(cn->values[0].sint);
-								} else if (flow->expressions[0]->type == Node::NODE_TYPE_VARIABLE) {
-									VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]);
-									if (!vn) {
-										return ERR_PARSE_ERROR;
-									}
-									Vector<Scalar> v = { Scalar() };
-									_find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v);
-									if (constants.has(v[0].sint)) {
-										_set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
-										return ERR_PARSE_ERROR;
-									}
-									constants.insert(v[0].sint);
-								}
-							} else if (flow->flow_op == FLOW_OP_DEFAULT) {
-								continue;
-							} else {
-								return ERR_PARSE_ERROR;
-							}
-						} else {
-							return ERR_PARSE_ERROR;
-						}
-					}
 					break;
 					break;
 				}
 				}
 			}
 			}
@@ -8184,36 +8156,77 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 
 
 			if (!tk.is_integer_constant()) {
 			if (!tk.is_integer_constant()) {
 				bool correct_constant_expression = false;
 				bool correct_constant_expression = false;
-				DataType data_type;
 
 
 				if (tk.type == TK_IDENTIFIER) {
 				if (tk.type == TK_IDENTIFIER) {
+					DataType data_type;
 					bool is_const;
 					bool is_const;
+
 					_find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const);
 					_find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const);
-					if (is_const) {
-						if (data_type == TYPE_INT) {
-							correct_constant_expression = true;
-						}
+					if (is_const && data_type == p_block->expected_type) {
+						correct_constant_expression = true;
 					}
 					}
 				}
 				}
+
 				if (!correct_constant_expression) {
 				if (!correct_constant_expression) {
-					_set_error(RTR("Expected an integer constant."));
+					if (p_block->expected_type == TYPE_UINT) {
+						_set_error(RTR("Expected an unsigned integer constant."));
+					} else {
+						_set_error(RTR("Expected an integer constant."));
+					}
 					return ERR_PARSE_ERROR;
 					return ERR_PARSE_ERROR;
 				}
 				}
 
 
 				VariableNode *vn = alloc_node<VariableNode>();
 				VariableNode *vn = alloc_node<VariableNode>();
 				vn->name = tk.text;
 				vn->name = tk.text;
+				{
+					Vector<Scalar> v;
+					DataType data_type;
+
+					_find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, nullptr, nullptr, nullptr, &v);
+					if (data_type == TYPE_INT) {
+						if (p_block->constants.has(v[0].sint)) {
+							_set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
+							return ERR_PARSE_ERROR;
+						}
+						p_block->constants.insert(v[0].sint);
+					} else {
+						if (p_block->constants.has(v[0].uint)) {
+							_set_error(vformat(RTR("Duplicated case label: %d."), v[0].uint));
+							return ERR_PARSE_ERROR;
+						}
+						p_block->constants.insert(v[0].uint);
+					}
+				}
 				n = vn;
 				n = vn;
 			} else {
 			} else {
+				ConstantNode *cn = alloc_node<ConstantNode>();
 				Scalar v;
 				Scalar v;
-				if (tk.type == TK_UINT_CONSTANT) {
+				if (p_block->expected_type == TYPE_UINT) {
+					if (tk.type != TK_UINT_CONSTANT) {
+						_set_error(RTR("Expected an unsigned integer constant."));
+						return ERR_PARSE_ERROR;
+					}
 					v.uint = (uint32_t)tk.constant;
 					v.uint = (uint32_t)tk.constant;
+					if (p_block->constants.has(v.uint)) {
+						_set_error(vformat(RTR("Duplicated case label: %d."), v.uint));
+						return ERR_PARSE_ERROR;
+					}
+					p_block->constants.insert(v.uint);
+					cn->datatype = TYPE_UINT;
 				} else {
 				} else {
-					v.sint = (int)tk.constant * sign;
+					if (tk.type != TK_INT_CONSTANT) {
+						_set_error(RTR("Expected an integer constant."));
+						return ERR_PARSE_ERROR;
+					}
+					v.sint = (int32_t)tk.constant * sign;
+					if (p_block->constants.has(v.sint)) {
+						_set_error(vformat(RTR("Duplicated case label: %d."), v.sint));
+						return ERR_PARSE_ERROR;
+					}
+					p_block->constants.insert(v.sint);
+					cn->datatype = TYPE_INT;
 				}
 				}
-
-				ConstantNode *cn = alloc_node<ConstantNode>();
 				cn->values.push_back(v);
 				cn->values.push_back(v);
-				cn->datatype = (tk.type == TK_UINT_CONSTANT ? TYPE_UINT : TYPE_INT);
 				n = cn;
 				n = cn;
 			}
 			}
 
 

+ 3 - 0
servers/rendering/shader_language.h

@@ -544,6 +544,9 @@ public:
 		bool use_comma_between_statements = false;
 		bool use_comma_between_statements = false;
 		bool use_op_eval = true;
 		bool use_op_eval = true;
 
 
+		DataType expected_type = TYPE_VOID;
+		HashSet<int> constants;
+
 		BlockNode() :
 		BlockNode() :
 				Node(NODE_TYPE_BLOCK) {}
 				Node(NODE_TYPE_BLOCK) {}
 	};
 	};