+void *psi_array_to_struct(decl_struct *s, HashTable *arr)
+{
+ size_t i, j = 0;
+ char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
+
+ if (arr) for (i = 0; i < s->args->count; ++i) {
+ decl_arg *darg = s->args->args[i];
+ zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
+
+ if (entry) {
+ impl_val val;
+ void *tmp = NULL;
+
+ memset(&tmp, 0, sizeof(tmp));
+ psi_from_zval(&val, darg, entry, &tmp);
+ memcpy(mem + darg->layout->pos, &val, darg->layout->len);
+ if (tmp) {
+ ((void **)(mem + s->size))[j++] = tmp;
+ }
+ }
+ }
+ return mem;
+}
+
+static inline impl_val *struct_member_ref(decl_arg *set_arg, impl_val *struct_ptr, impl_val **to_free) {
+ void *ptr = (char *) struct_ptr->ptr + set_arg->layout->pos;
+ impl_val *val = enref_impl_val(ptr, set_arg->var);
+
+ if (val != ptr) {
+ *to_free = val;
+ }
+
+ return val;
+}
+void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
+{
+ size_t i;
+ decl_var *var = set->vars->vars[0];
+ token_t t = real_decl_type(var->arg->type)->type;
+ impl_val tmp, *ret_val = deref_impl_val(r_val, var);
+
+ array_init(return_value);
+
+ if (t == PSI_T_STRUCT) {
+ // decl_struct *s = real_decl_type(var->arg->type)->strct;
+
+ if (set->count) {
+ /* explicit member casts */
+ for (i = 0; i < set->count; ++i) {
+ set_value *sub_set = set->inner[i];
+ decl_var *sub_var = sub_set->vars->vars[0];
+
+ sub_set->outer.val = r_val;
+
+ if (sub_var->arg) {
+ impl_val *tmp = NULL, *val;
+ zval ztmp;
+
+ val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var);
+ sub_set->func->handler(&ztmp, sub_set, val);
+ add_assoc_zval(return_value, sub_var->name, &ztmp);
+
+ if (tmp) {
+ free(tmp);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ if (var->arg->var->array_size) {
+ /* to_array(foo[NUMBER]) */
+ for (i = 0; i < var->arg->var->array_size; ++i) {
+ size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
+ impl_val *ptr = iterate(ret_val, size, i, &tmp);
+ zval ele;
+
+ switch (t) {
+ case PSI_T_FLOAT:
+ ZVAL_DOUBLE(&ele, (double) ptr->fval);
+ break;
+ case PSI_T_DOUBLE:
+ ZVAL_DOUBLE(&ele, ptr->dval);
+ break;
+ default:
+ ZVAL_LONG(&ele, ptr->lval);
+ break;
+ }
+
+ add_next_index_zval(return_value, &ele);
+ }
+ return;
+ } else if (set->vars->count > 1) {
+ /* to_array(arr_var, cnt_var[, cnt_var...], to_int(*arr_var))
+ * check for length in second var
+ */
+ size_t count = 0;
+ zval ele;
+
+ if (set->outer.set) {
+ /* struct */
+ for (i = 1; i < set->vars->count; ++i) {
+ impl_val *tmp = NULL, *cnt_val;
+ decl_var *cnt_var = set->vars->vars[i];
+
+ cnt_val = struct_member_ref(cnt_var->arg, set->outer.val, &tmp);
+ count += deref_impl_val(cnt_val, cnt_var)->lval;
+
+ if (tmp) {
+ free(tmp);
+ }
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ for (i = 0; i < count; ++i) {
+ size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
+ impl_val *ptr = iterate(ret_val, size, i, &tmp);
+
+ set->inner[0]->func->handler(&ele, set->inner[0], ptr);
+ add_next_index_zval(return_value, &ele);
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+}
+
+static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)