+#include "Zend/zend_interfaces.h"
+#include "ext/spl/spl_iterators.h"
+
+zend_long psi_zval_count(zval *zvalue)
+{
+ /* mimic PHP count() */
+ zend_long count;
+ zval retval;
+
+ switch (Z_TYPE_P(zvalue)) {
+ default:
+ count = 1;
+ break;
+ case IS_NULL:
+ count = 0;
+ break;
+ case IS_ARRAY:
+ count = zend_array_count(Z_ARRVAL_P(zvalue));
+ break;
+ case IS_OBJECT:
+ count = 1;
+ if (Z_OBJ_HT_P(zvalue)->count_elements) {
+ if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(Z_OBJ_P(zvalue), &count)) {
+ break;
+ }
+ }
+
+ if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
+ zend_call_method_with_0_params(Z_OBJ_P(zvalue), NULL, NULL, "count", &retval);
+ if (Z_TYPE(retval) != IS_UNDEF) {
+ count = zval_get_long(&retval);
+ zval_ptr_dtor(&retval);
+ }
+ }
+ break;
+ }
+
+ return count;
+}
+
+int psi_internal_type(struct psi_impl_type *type)
+{
+ switch (type->type) {
+ case PSI_T_BOOL:
+ return _IS_BOOL;
+ case PSI_T_INT:
+ return IS_LONG;
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ return IS_DOUBLE;
+ case PSI_T_STRING:
+ return IS_STRING;
+ case PSI_T_ARRAY:
+ return IS_ARRAY;
+ default:
+ return 0;
+ }
+}
+
+zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
+{
+ size_t i = 0, argc = psi_plist_count(impl->func->args);
+ zend_internal_arg_info *aip;
+ zend_internal_function_info *fi;
+ struct psi_impl_arg *iarg;
+ zend_type rtyp = ZEND_TYPE_INIT_CODE(psi_internal_type(impl->func->return_type), 1, _ZEND_ARG_INFO_FLAGS(impl->func->return_reference, impl->func->vararg));
+
+ aip = pecalloc(argc + 1 + !!impl->func->vararg, sizeof(*aip), 1);
+
+ fi = (zend_internal_function_info *) &aip[0];
+ fi->required_num_args = psi_impl_num_min_args(impl);
+ fi->type = rtyp;
+
+ if (impl->func->vararg) {
+ struct psi_impl_arg *vararg = impl->func->vararg;
+ zend_internal_arg_info *ai = &aip[argc];
+ zend_type atyp = ZEND_TYPE_INIT_CODE(psi_internal_type(vararg->type), 1, _ZEND_ARG_INFO_FLAGS(vararg->var->reference, 1));
+
+ ai->name = &vararg->var->name->val[1];
+ ai->type = atyp;
+ }
+
+ while (psi_plist_get(impl->func->args, i++, &iarg)) {
+ zend_internal_arg_info *ai = &aip[i];
+ zend_type atyp = ZEND_TYPE_INIT_CODE(psi_internal_type(iarg->type), 1, _ZEND_ARG_INFO_FLAGS(iarg->var->reference, 0));
+
+ ai->name = &iarg->var->name->val[1];
+ ai->type = atyp;
+ }
+
+ return aip;
+}
+
+/*
+ * return void(dvar)
+ */
+void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)