Allow booleanization of all types

We now allow booleanization of all types. This means that empty versions
of all types now evaluate to false. So a Vector2(0,0), Dictionary(),
etc.

This allows you to write GDScript like:
if not Dictionary():
  print("Empty dict")

Booleanization can now also no longer fail. There is no more valid flag,
this changes Variant and GDNative API.
This commit is contained in:
Hein-Pieter van Braam 2017-09-18 20:02:47 +02:00
parent 85641c545b
commit 833c3917b2
6 changed files with 20 additions and 105 deletions

View File

@ -390,7 +390,7 @@ public:
uint32_t hash() const;
bool hash_compare(const Variant &p_variant) const;
bool booleanize(bool &valid) const;
bool booleanize() const;
void static_assign(const Variant &p_variant);
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);

View File

@ -143,56 +143,13 @@
Variant::operator bool() const {
bool b;
return booleanize(b);
return booleanize();
}
bool Variant::booleanize(bool &r_valid) const {
r_valid = true;
switch (type) {
case NIL:
return false;
case BOOL:
return _data._bool;
case INT:
return _data._int;
case REAL:
return _data._real;
case STRING:
return (*reinterpret_cast<const String *>(_data._mem)) != "";
case VECTOR2:
case RECT2:
case TRANSFORM2D:
case VECTOR3:
case PLANE:
case RECT3:
case QUAT:
case BASIS:
case TRANSFORM:
case COLOR:
case _RID:
return (*reinterpret_cast<const RID *>(_data._mem)).is_valid();
case OBJECT:
return _get_obj().obj;
case NODE_PATH:
return (*reinterpret_cast<const NodePath *>(_data._mem)) != NodePath();
case DICTIONARY:
case ARRAY:
case POOL_BYTE_ARRAY:
case POOL_INT_ARRAY:
case POOL_REAL_ARRAY:
case POOL_STRING_ARRAY:
case POOL_VECTOR2_ARRAY:
case POOL_VECTOR3_ARRAY:
case POOL_COLOR_ARRAY:
r_valid = false;
return false;
default: {
}
}
return false;
// We consider all unitialized or empty types to be false based on the type's
// zeroiness.
bool Variant::booleanize() const {
return !is_zero();
}
#define _RETURN(m_what) \
@ -403,12 +360,6 @@ bool Variant::booleanize(bool &r_valid) const {
_RETURN(sum); \
}
#define DEFAULT_OP_FAIL(m_name) \
case m_name: { \
r_valid = false; \
return; \
}
void Variant::evaluate(const Operator &p_op, const Variant &p_a,
const Variant &p_b, Variant &r_ret, bool &r_valid) {
@ -1177,12 +1128,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
SWITCH_OP(math, OP_AND, p_a.type) {
CASE_TYPE_ALL(math, OP_AND) {
bool l = p_a.booleanize(r_valid);
if (!r_valid)
return;
bool r = p_b.booleanize(r_valid);
if (!r_valid)
return;
bool l = p_a.booleanize();
bool r = p_b.booleanize();
_RETURN(l && r);
}
@ -1190,12 +1137,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
SWITCH_OP(math, OP_OR, p_a.type) {
CASE_TYPE_ALL(math, OP_OR) {
bool l = p_a.booleanize(r_valid);
if (!r_valid)
return;
bool r = p_b.booleanize(r_valid);
if (!r_valid)
return;
bool l = p_a.booleanize();
bool r = p_b.booleanize();
_RETURN(l || r);
}
@ -1203,12 +1146,8 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
SWITCH_OP(math, OP_XOR, p_a.type) {
CASE_TYPE_ALL(math, OP_XOR) {
bool l = p_a.booleanize(r_valid);
if (!r_valid)
return;
bool r = p_b.booleanize(r_valid);
if (!r_valid)
return;
bool l = p_a.booleanize();
bool r = p_b.booleanize();
_RETURN((l || r) && !(l && r));
}
@ -1216,9 +1155,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
SWITCH_OP(math, OP_NOT, p_a.type) {
CASE_TYPE_ALL(math, OP_NOT) {
bool l = p_a.booleanize(r_valid);
if (!r_valid)
return;
bool l = p_a.booleanize();
_RETURN(!l);
}
}

View File

@ -480,10 +480,9 @@ godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const g
return self->hash_compare(*other);
}
godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self, godot_bool *r_valid) {
godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self) {
const Variant *self = (const Variant *)p_self;
bool &valid = *r_valid;
return self->booleanize(valid);
return self->booleanize();
}
void GDAPI godot_variant_destroy(godot_variant *p_self) {

View File

@ -190,7 +190,7 @@ godot_bool GDAPI godot_variant_operator_less(const godot_variant *p_self, const
godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const godot_variant *p_other);
godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self, godot_bool *r_valid);
godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self);
void GDAPI godot_variant_destroy(godot_variant *p_self);

View File

@ -534,7 +534,7 @@ extern "C" {
GDAPI_FUNC(godot_variant_operator_equal, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
GDAPI_FUNC(godot_variant_operator_less, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
GDAPI_FUNC(godot_variant_hash_compare, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
GDAPI_FUNC(godot_variant_booleanize, godot_bool, const godot_variant *p_self, godot_bool *r_valid) \
GDAPI_FUNC(godot_variant_booleanize, godot_bool, const godot_variant *p_self) \
GDAPI_FUNC_VOID(godot_variant_destroy, godot_variant *p_self) \
GDAPI_FUNC_VOID(godot_string_new, godot_string *r_dest) \
GDAPI_FUNC_VOID(godot_string_new_copy, godot_string *r_dest, const godot_string *p_src) \

View File

@ -982,15 +982,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(test, 1);
bool valid;
bool result = test->booleanize(valid);
#ifdef DEBUG_ENABLED
if (!valid) {
bool result = test->booleanize();
err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
break;
}
#endif
if (result) {
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
@ -1006,15 +999,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(test, 1);
bool valid;
bool result = test->booleanize(valid);
#ifdef DEBUG_ENABLED
if (!valid) {
bool result = test->booleanize();
err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
break;
}
#endif
if (!result) {
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
@ -1107,14 +1093,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(test, 1);
#ifdef DEBUG_ENABLED
bool valid;
bool result = test->booleanize(valid);
if (!valid) {
err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
break;
}
bool result = test->booleanize();
if (!result) {