diff options
Diffstat (limited to 'modules/gdscript/gdscript_analyzer.cpp')
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 82 |
1 files changed, 74 insertions, 8 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 4098425518..1e72216ad2 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -71,6 +71,10 @@ static StringName get_real_class_name(const StringName &p_source) { return p_source; } +void GDScriptAnalyzer::cleanup() { + underscore_map.clear(); +} + static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) { GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -494,7 +498,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas if (member.variable->initializer != nullptr) { if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { #ifdef DEBUG_ENABLED parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -989,7 +993,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable if (p_variable->initializer != nullptr) { if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); #ifdef DEBUG_ENABLED } else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -1369,11 +1373,61 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!is_type_compatible(p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), true)) { - if (p_assignment->assignee->get_datatype().is_hard_type()) { - push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + Variant::Operator vop = Variant::Operator::OP_EQUAL; + switch (p_assignment->operation) { + case GDScriptParser::AssignmentNode::OP_NONE: + vop = Variant::Operator::OP_EQUAL; + break; + case GDScriptParser::AssignmentNode::OP_ADDITION: + vop = Variant::Operator::OP_ADD; + break; + case GDScriptParser::AssignmentNode::OP_SUBTRACTION: + vop = Variant::Operator::OP_SUBTRACT; + break; + case GDScriptParser::AssignmentNode::OP_MULTIPLICATION: + vop = Variant::Operator::OP_MULTIPLY; + break; + case GDScriptParser::AssignmentNode::OP_DIVISION: + vop = Variant::Operator::OP_DIVIDE; + break; + case GDScriptParser::AssignmentNode::OP_MODULO: + vop = Variant::Operator::OP_MODULE; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_LEFT: + vop = Variant::Operator::OP_SHIFT_LEFT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_RIGHT: + vop = Variant::Operator::OP_SHIFT_RIGHT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_AND: + vop = Variant::Operator::OP_BIT_AND; + break; + case GDScriptParser::AssignmentNode::OP_BIT_OR: + vop = Variant::Operator::OP_BIT_OR; + break; + case GDScriptParser::AssignmentNode::OP_BIT_XOR: + vop = Variant::Operator::OP_BIT_XOR; + break; + } + + if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) { + bool compatible = true; + GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype(); + if (vop != Variant::OP_EQUAL) { + op_type = get_operation_type(vop, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible); + } + + if (compatible) { + compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true); + if (!compatible) { + if (p_assignment->assignee->get_datatype().is_hard_type()) { + push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + } else { + // TODO: Warning in this case. + } + } } else { - // TODO: Warning in this case. + push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment); } } @@ -1488,7 +1542,19 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) { p_binary_op->is_constant = true; if (p_binary_op->variant_op < Variant::OP_MAX) { - p_binary_op->reduced_value = Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value); + bool valid = false; + Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value, p_binary_op->reduced_value, valid); + if (!valid) { + if (p_binary_op->reduced_value.get_type() == Variant::STRING) { + push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + } else { + push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)", + Variant::get_operator_name(p_binary_op->variant_op), + Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()), + Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())), + p_binary_op); + } + } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { GDScriptParser::DataType test_type = right_type; @@ -2019,7 +2085,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::ClassNode *outer = base_class->outer; while (outer != nullptr) { if (outer->has_member(name)) { - const GDScriptParser::ClassNode::Member &member = base_class->get_member(name); + const GDScriptParser::ClassNode::Member &member = outer->get_member(name); if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) { // TODO: Make sure loops won't cause problem. And make special error message for those. // For out-of-order resolution: |