Skip to content

Commit

Permalink
Allow booleanization of all types
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hpvb committed Sep 19, 2017
1 parent 85641c5 commit 833c391
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 105 deletions.
2 changes: 1 addition & 1 deletion core/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ class Variant {
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);
Expand Down
87 changes: 12 additions & 75 deletions core/variant_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down Expand Up @@ -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) {

Expand Down Expand Up @@ -1177,48 +1128,34 @@ 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);
}
}

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);
}
}

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));
}
}

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);
}
}
Expand Down
5 changes: 2 additions & 3 deletions modules/gdnative/gdnative/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/include/gdnative/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/include/gdnative_api_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
27 changes: 3 additions & 24 deletions modules/gdscript/gd_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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) {

Expand Down

0 comments on commit 833c391

Please sign in to comment.