Merge pull request #74741 from vnen/variant-not-for-everyone

Allow boolean operators for all Variant types
This commit is contained in:
Rémi Verschelde 2023-06-18 16:28:10 +02:00
commit 1a62f1e4fc
No known key found for this signature in database
GPG Key ID: C3336907360768E1
6 changed files with 639 additions and 3 deletions

View File

@ -900,6 +900,39 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL);
register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL);
register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL);
register_op<OperatorEvaluatorNot<String>>(Variant::OP_NOT, Variant::STRING, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector2>>(Variant::OP_NOT, Variant::VECTOR2, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector2i>>(Variant::OP_NOT, Variant::VECTOR2I, Variant::NIL);
register_op<OperatorEvaluatorNot<Rect2>>(Variant::OP_NOT, Variant::RECT2, Variant::NIL);
register_op<OperatorEvaluatorNot<Rect2i>>(Variant::OP_NOT, Variant::RECT2I, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector3>>(Variant::OP_NOT, Variant::VECTOR3, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector3i>>(Variant::OP_NOT, Variant::VECTOR3I, Variant::NIL);
register_op<OperatorEvaluatorNot<Transform2D>>(Variant::OP_NOT, Variant::TRANSFORM2D, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector4>>(Variant::OP_NOT, Variant::VECTOR4, Variant::NIL);
register_op<OperatorEvaluatorNot<Vector4i>>(Variant::OP_NOT, Variant::VECTOR4I, Variant::NIL);
register_op<OperatorEvaluatorNot<Plane>>(Variant::OP_NOT, Variant::PLANE, Variant::NIL);
register_op<OperatorEvaluatorNot<Quaternion>>(Variant::OP_NOT, Variant::QUATERNION, Variant::NIL);
register_op<OperatorEvaluatorNot<::AABB>>(Variant::OP_NOT, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorNot<Basis>>(Variant::OP_NOT, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorNot<Transform3D>>(Variant::OP_NOT, Variant::TRANSFORM3D, Variant::NIL);
register_op<OperatorEvaluatorNot<Projection>>(Variant::OP_NOT, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorNot<Color>>(Variant::OP_NOT, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorNot<StringName>>(Variant::OP_NOT, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorNot<NodePath>>(Variant::OP_NOT, Variant::NODE_PATH, Variant::NIL);
register_op<OperatorEvaluatorNot<::RID>>(Variant::OP_NOT, Variant::RID, Variant::NIL);
register_op<OperatorEvaluatorNot<Callable>>(Variant::OP_NOT, Variant::CALLABLE, Variant::NIL);
register_op<OperatorEvaluatorNot<Signal>>(Variant::OP_NOT, Variant::SIGNAL, Variant::NIL);
register_op<OperatorEvaluatorNot<Dictionary>>(Variant::OP_NOT, Variant::DICTIONARY, Variant::NIL);
register_op<OperatorEvaluatorNot<Array>>(Variant::OP_NOT, Variant::ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedByteArray>>(Variant::OP_NOT, Variant::PACKED_BYTE_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedInt32Array>>(Variant::OP_NOT, Variant::PACKED_INT32_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedInt64Array>>(Variant::OP_NOT, Variant::PACKED_INT64_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedFloat32Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT32_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedFloat64Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT64_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedStringArray>>(Variant::OP_NOT, Variant::PACKED_STRING_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedVector2Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR2_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedVector3Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR3_ARRAY, Variant::NIL);
register_op<OperatorEvaluatorNot<PackedColorArray>>(Variant::OP_NOT, Variant::PACKED_COLOR_ARRAY, Variant::NIL);
register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN);

View File

@ -805,14 +805,14 @@ class OperatorEvaluatorNot {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
*r_ret = !a;
*r_ret = a == A();
r_valid = true;
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
*VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left);
*VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == A();
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
PtrToArg<bool>::encode(!PtrToArg<A>::convert(left));
PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == A(), r_ret);
}
static Variant::Type get_return_type() { return Variant::BOOL; }
};

View File

@ -4955,6 +4955,17 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
}
GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
if (p_operation == Variant::OP_AND || p_operation == Variant::OP_OR) {
// Those work for any type of argument and always return a boolean.
// They don't use the Variant operator since they have short-circuit semantics.
r_valid = true;
GDScriptParser::DataType result;
result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = Variant::BOOL;
return result;
}
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;

View File

@ -0,0 +1,347 @@
extends Resource
signal foo
func test():
var x
# TYPE_NIL
x = null
prints("TYPE_NIL")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_BOOL
x = true
prints("TYPE_BOOL")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_INT
x = 1
prints("TYPE_INT")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_FLOAT
x = 1.1
prints("TYPE_FLOAT")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_STRING
x = "foo"
prints("TYPE_STRING")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR2
x = Vector2(1, 1)
prints("TYPE_VECTOR2")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR2I
x = Vector2i(1, 1)
prints("TYPE_VECTOR2I")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_RECT2
x = Rect2(1, 1, 1, 1)
prints("TYPE_RECT2")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_RECT2I
x = Rect2i(1, 1, 1, 1)
prints("TYPE_RECT2I")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR3
x = Vector3(1, 1, 1)
prints("TYPE_VECTOR3")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR3I
x = Vector3i(1, 1, 1)
prints("TYPE_VECTOR3I")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_TRANSFORM2D
x = Transform2D.IDENTITY
prints("TYPE_TRANSFORM2D")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR4
x = Vector4(1, 1, 1, 1)
prints("TYPE_VECTOR4")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_VECTOR4I
x = Vector4i(1, 1, 1, 1)
prints("TYPE_VECTOR4I")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PLANE
x = Plane.PLANE_XY
prints("TYPE_PLANE")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_QUATERNION
x = Quaternion.IDENTITY
prints("TYPE_QUATERNION")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_AABB
x = AABB(Vector3.ONE, Vector3.ONE)
prints("TYPE_AABB")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_BASIS
x = Basis.IDENTITY
prints("TYPE_BASIS")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_TRANSFORM3D
x = Transform3D.IDENTITY
prints("TYPE_TRANSFORM3D")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PROJECTION
x = Projection.IDENTITY
prints("TYPE_PROJECTION")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_COLOR
x = Color.WHITE
prints("TYPE_COLOR")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_STRING_NAME
x = &"name"
prints("TYPE_STRING_NAME")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_NODE_PATH
x = ^"path"
prints("TYPE_NODE_PATH")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_RID
x = get_rid()
prints("TYPE_RID")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_OBJECT
x = self
prints("TYPE_OBJECT")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_CALLABLE
x = test
prints("TYPE_CALLABLE")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_SIGNAL
x = foo
prints("TYPE_SIGNAL")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_DICTIONARY
x = { a = 1}
prints("TYPE_DICTIONARY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_ARRAY
x = [1]
prints("TYPE_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_BYTE_ARRAY
x = PackedByteArray([1])
prints("TYPE_PACKED_BYTE_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_INT32_ARRAY
x = PackedInt32Array([1])
prints("TYPE_PACKED_INT32_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_INT64_ARRAY
x = PackedInt64Array([1])
prints("TYPE_PACKED_INT64_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_FLOAT32_ARRAY
x = PackedFloat32Array([1])
prints("TYPE_PACKED_FLOAT32_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_FLOAT64_ARRAY
x = PackedFloat64Array([1])
prints("TYPE_PACKED_FLOAT64_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_STRING_ARRAY
x = PackedStringArray(["1"])
prints("TYPE_PACKED_STRING_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_VECTOR2_ARRAY
x = PackedVector2Array([Vector2.ONE])
prints("TYPE_PACKED_VECTOR2_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_VECTOR3_ARRAY
x = PackedVector3Array([Vector3.ONE])
prints("TYPE_PACKED_VECTOR3_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)
# TYPE_PACKED_COLOR_ARRAY
x = PackedColorArray([Color.WHITE])
prints("TYPE_PACKED_COLOR_ARRAY")
prints(not x)
prints(x and false)
prints(x and true)
prints(x or false)
prints(x or true)

View File

@ -0,0 +1,229 @@
GDTEST_OK
TYPE_NIL
true
false
false
false
true
TYPE_BOOL
false
false
true
true
true
TYPE_INT
false
false
true
true
true
TYPE_FLOAT
false
false
true
true
true
TYPE_STRING
false
false
true
true
true
TYPE_VECTOR2
false
false
true
true
true
TYPE_VECTOR2I
false
false
true
true
true
TYPE_RECT2
false
false
true
true
true
TYPE_RECT2I
false
false
true
true
true
TYPE_VECTOR3
false
false
true
true
true
TYPE_VECTOR3I
false
false
true
true
true
TYPE_TRANSFORM2D
true
false
false
false
true
TYPE_VECTOR4
false
false
true
true
true
TYPE_VECTOR4I
false
false
true
true
true
TYPE_PLANE
false
false
true
true
true
TYPE_QUATERNION
true
false
false
false
true
TYPE_AABB
false
false
true
true
true
TYPE_BASIS
true
false
false
false
true
TYPE_TRANSFORM3D
true
false
false
false
true
TYPE_PROJECTION
true
false
false
false
true
TYPE_COLOR
false
false
true
true
true
TYPE_STRING_NAME
false
false
true
true
true
TYPE_NODE_PATH
false
false
true
true
true
TYPE_RID
true
false
false
false
true
TYPE_OBJECT
false
false
true
true
true
TYPE_CALLABLE
false
false
true
true
true
TYPE_SIGNAL
false
false
true
true
true
TYPE_DICTIONARY
false
false
true
true
true
TYPE_ARRAY
false
false
true
true
true
TYPE_PACKED_BYTE_ARRAY
false
false
true
true
true
TYPE_PACKED_INT32_ARRAY
false
false
true
true
true
TYPE_PACKED_INT64_ARRAY
false
false
true
true
true
TYPE_PACKED_FLOAT32_ARRAY
false
false
true
true
true
TYPE_PACKED_FLOAT64_ARRAY
false
false
true
true
true
TYPE_PACKED_STRING_ARRAY
false
false
true
true
true
TYPE_PACKED_VECTOR2_ARRAY
false
false
true
true
true
TYPE_PACKED_VECTOR3_ARRAY
false
false
true
true
true
TYPE_PACKED_COLOR_ARRAY
false
false
true
true
true

View File

@ -1171,6 +1171,22 @@ TEST_CASE("[Variant] Utility functions") {
}
}
TEST_CASE("[Variant] Operator NOT") {
// Verify that operator NOT works for all types and is consistent with booleanize().
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
Variant value;
Callable::CallError err;
Variant::construct((Variant::Type)i, value, nullptr, 0, err);
REQUIRE_EQ(err.error, Callable::CallError::CALL_OK);
Variant result = Variant::evaluate(Variant::OP_NOT, value, Variant());
REQUIRE_EQ(result.get_type(), Variant::BOOL);
CHECK_EQ(!value.booleanize(), result.operator bool());
}
}
} // namespace TestVariant
#endif // TEST_VARIANT_H