patch 9.0.1786: Vim9: need instanceof() function

Problem:  Vim9: need instanceof() function
Solution: Implement instanceof() builtin

Implemented in the same form as Python's isinstance because it allows
for checking multiple class types at the same time.

closes: #12867

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: LemonBoy <thatlemon@gmail.com>
diff --git a/src/vim9class.c b/src/vim9class.c
index 00b1f7d..4f86a6f 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -1913,5 +1913,69 @@
     return did_free;
 }
 
+/*
+ * Return TRUE when the class "cl", its base class or one of the implemented interfaces
+ * matches the class "other_cl".
+ */
+    int
+class_instance_of(class_T *cl, class_T *other_cl)
+{
+    if (cl == other_cl)
+	return TRUE;
+
+    // Recursively check the base classes.
+    for (; cl != NULL; cl = cl->class_extends)
+    {
+	if (cl == other_cl)
+	    return TRUE;
+	// Check the implemented interfaces.
+	for (int i = cl->class_interface_count - 1; i >= 0; --i)
+	    if (cl->class_interfaces_cl[i] == other_cl)
+		return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * "instanceof(object, classinfo)" function
+ */
+    void
+f_instanceof(typval_T *argvars, typval_T *rettv)
+{
+    typval_T	*object_tv = &argvars[0];
+    typval_T	*classinfo_tv = &argvars[1];
+    listitem_T	*li;
+
+    rettv->vval.v_number = VVAL_FALSE;
+
+    if (check_for_object_arg(argvars, 0) == FAIL
+	    || check_for_class_or_list_arg(argvars, 1) == FAIL)
+	return;
+
+    if (classinfo_tv->v_type == VAR_LIST)
+    {
+	FOR_ALL_LIST_ITEMS(classinfo_tv->vval.v_list, li)
+	{
+	    if (li->li_tv.v_type != VAR_CLASS)
+	    {
+		emsg(_(e_class_required));
+		return;
+	    }
+
+	    if (class_instance_of(object_tv->vval.v_object->obj_class,
+			li->li_tv.vval.v_class) == TRUE)
+	    {
+		rettv->vval.v_number = VVAL_TRUE;
+		return;
+	    }
+	}
+    }
+    else if (classinfo_tv->v_type == VAR_CLASS)
+    {
+	rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
+		classinfo_tv->vval.v_class);
+    }
+}
 
 #endif // FEAT_EVAL