summaryrefslogtreecommitdiff
path: root/modules/gdscript/gdscript_vm.cpp
diff options
context:
space:
mode:
authorDmitrii Maganov <vonagam@gmail.com>2023-02-17 01:16:24 +0200
committerDmitrii Maganov <vonagam@gmail.com>2023-02-17 19:57:18 +0200
commit8fe023ad93119061cda4730d1b0ba1946f15c515 (patch)
tree519b6b608fa8605926ad0b0db8075bf1be086fea /modules/gdscript/gdscript_vm.cpp
parent28db611f0f27c37d2d02fc986e9edbb8a8725267 (diff)
GDScript: Rework type check
Diffstat (limited to 'modules/gdscript/gdscript_vm.cpp')
-rw-r--r--modules/gdscript/gdscript_vm.cpp134
1 files changed, 70 insertions, 64 deletions
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index fd8875d8b1..b9576ee517 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -201,8 +201,10 @@ void (*type_init_function_table[])(Variant *) = {
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
&&OPCODE_OPERATOR_VALIDATED, \
- &&OPCODE_EXTENDS_TEST, \
- &&OPCODE_IS_BUILTIN, \
+ &&OPCODE_TYPE_TEST_BUILTIN, \
+ &&OPCODE_TYPE_TEST_ARRAY, \
+ &&OPCODE_TYPE_TEST_NATIVE, \
+ &&OPCODE_TYPE_TEST_SCRIPT, \
&&OPCODE_SET_KEYED, \
&&OPCODE_SET_KEYED_VALIDATED, \
&&OPCODE_SET_INDEXED_VALIDATED, \
@@ -743,91 +745,95 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_EXTENDS_TEST) {
+ OPCODE(OPCODE_TYPE_TEST_BUILTIN) {
CHECK_SPACE(4);
- GET_VARIANT_PTR(a, 0);
- GET_VARIANT_PTR(b, 1);
- GET_VARIANT_PTR(dst, 2);
-
-#ifdef DEBUG_ENABLED
- if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) {
- err_text = "Right operand of 'is' is not a class.";
- OPCODE_BREAK;
- }
-#endif
+ GET_VARIANT_PTR(dst, 0);
+ GET_VARIANT_PTR(value, 1);
- bool extends_ok = false;
- if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) {
-#ifdef DEBUG_ENABLED
- bool was_freed;
- Object *obj_A = a->get_validated_object_with_check(was_freed);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 3];
+ GD_ERR_BREAK(builtin_type < 0 || builtin_type >= Variant::VARIANT_MAX);
- if (was_freed) {
- err_text = "Left operand of 'is' is a previously freed instance.";
- OPCODE_BREAK;
- }
+ *dst = value->get_type() == builtin_type;
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
- Object *obj_B = b->get_validated_object_with_check(was_freed);
+ OPCODE(OPCODE_TYPE_TEST_ARRAY) {
+ CHECK_SPACE(6);
- if (was_freed) {
- err_text = "Right operand of 'is' is a previously freed instance.";
- OPCODE_BREAK;
- }
-#else
+ GET_VARIANT_PTR(dst, 0);
+ GET_VARIANT_PTR(value, 1);
- Object *obj_A = *a;
- Object *obj_B = *b;
-#endif // DEBUG_ENABLED
+ GET_VARIANT_PTR(script_type, 2);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 4];
+ int native_type_idx = _code_ptr[ip + 5];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
- GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
+ bool result = false;
+ if (value->get_type() == Variant::ARRAY) {
+ Array *array = VariantInternal::get_array(value);
+ result = array->get_typed_builtin() == ((uint32_t)builtin_type) && array->get_typed_class_name() == native_type && array->get_typed_script() == *script_type && array->get_typed_class_name() == native_type;
+ }
- if (scr_B) {
- //if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this should return false.
+ *dst = result;
+ ip += 6;
+ }
+ DISPATCH_OPCODE;
- if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
- GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
- //bool found=false;
- while (cmp) {
- if (cmp == scr_B) {
- //inherits from script, all ok
- extends_ok = true;
- break;
- }
+ OPCODE(OPCODE_TYPE_TEST_NATIVE) {
+ CHECK_SPACE(4);
- cmp = cmp->_base;
- }
- }
+ GET_VARIANT_PTR(dst, 0);
+ GET_VARIANT_PTR(value, 1);
- } else {
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
+ int native_type_idx = _code_ptr[ip + 3];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
-#ifdef DEBUG_ENABLED
- if (!nc) {
- err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
- OPCODE_BREAK;
- }
-#endif
- extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
- }
+ bool was_freed = false;
+ Object *object = value->get_validated_object_with_check(was_freed);
+ if (was_freed) {
+ err_text = "Left operand of 'is' is a previously freed instance.";
+ OPCODE_BREAK;
}
- *dst = extends_ok;
+ *dst = object && ClassDB::is_parent_class(object->get_class_name(), native_type);
ip += 4;
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_IS_BUILTIN) {
+ OPCODE(OPCODE_TYPE_TEST_SCRIPT) {
CHECK_SPACE(4);
- GET_VARIANT_PTR(value, 0);
- GET_VARIANT_PTR(dst, 1);
- Variant::Type var_type = (Variant::Type)_code_ptr[ip + 3];
+ GET_VARIANT_PTR(dst, 0);
+ GET_VARIANT_PTR(value, 1);
- GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+ GET_VARIANT_PTR(type, 2);
+ Script *script_type = Object::cast_to<Script>(type->operator Object *());
+ GD_ERR_BREAK(!script_type);
+
+ bool was_freed = false;
+ Object *object = value->get_validated_object_with_check(was_freed);
+ if (was_freed) {
+ err_text = "Left operand of 'is' is a previously freed instance.";
+ OPCODE_BREAK;
+ }
+
+ bool result = false;
+ if (object && object->get_script_instance()) {
+ Script *script_ptr = object->get_script_instance()->get_script().ptr();
+ while (script_ptr) {
+ if (script_ptr == script_type) {
+ result = true;
+ break;
+ }
+ script_ptr = script_ptr->get_base_script().ptr();
+ }
+ }
- *dst = value->get_type() == var_type;
+ *dst = result;
ip += 4;
}
DISPATCH_OPCODE;