+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+
+ return align;
+}
+
+size_t psi_t_size(token_t t)
+{
+ size_t size;
+
+ switch (t) {
+ case PSI_T_INT8:
+ case PSI_T_UINT8:
+ size = 1;
+ break;
+ case PSI_T_INT16:
+ case PSI_T_UINT16:
+ size = 2;
+ break;
+ case PSI_T_INT:
+ size = sizeof(int);
+ break;
+ case PSI_T_INT32:
+ case PSI_T_UINT32:
+ size = 4;
+ break;
+ case PSI_T_INT64:
+ case PSI_T_UINT64:
+ size = 8;
+ break;
+ case PSI_T_FLOAT:
+ size = sizeof(float);
+ break;
+ case PSI_T_DOUBLE:
+ size = sizeof(double);
+ break;
+ case PSI_T_POINTER:
+ size = sizeof(char *);
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ return size;
+}
+
+size_t psi_t_align(token_t t, size_t s)
+{
+ size_t a = psi_t_alignment(t);
+ return ((s - 1) | (a - 1)) + 1;
+}
+
+static impl_val *iterate(impl_val *val, token_t t, unsigned i, impl_val *tmp)
+{
+ size_t size = psi_t_size(t);
+
+ memset(tmp, 0, sizeof(*tmp));
+ memcpy(tmp, val->ptr + size * i, size);
+ return tmp;
+}
+
+void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
+{
+ decl_type *type = real_decl_type(spec->type);
+
+ switch (type->type) {
+ case PSI_T_FLOAT:
+ mem->fval = (float) zval_get_double(zv);
+ break;
+ case PSI_T_DOUBLE:
+ mem->dval = zval_get_double(zv);
+ break;
+ case PSI_T_INT8:
+ case PSI_T_UINT8:
+ if (spec->var->pointer_level) {
+ zend_string *zs = zval_get_string(zv);
+ *tmp = mem->ptr = estrndup(zs->val, zs->len);
+ zend_string_release(zs);
+ break;
+ }
+ /* no break */
+ default:
+ mem->zend.lval = zval_get_long(zv);
+ break;
+ }
+}
+
+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;
+}
+
+void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
+{
+ zval ele;
+ unsigned i;
+ impl_val tmp;
+
+ array_init(return_value);
+
+ if (t == PSI_T_STRUCT) {
+ decl_struct *s = real_decl_type(var->arg->type)->strct;
+ ret_val = deref_impl_val(ret_val, var);
+
+ ZEND_ASSERT(s);
+ for (i = 0; i < s->args->count; ++i) {
+ decl_arg *darg = s->args->args[i];
+ impl_val tmp, tmp_ptr;
+ zval ztmp;
+ char *ptr = (char *) ret_val->ptr + darg->layout->pos;
+
+ tmp_ptr.ptr = &tmp;
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp, ptr, darg->layout->len);
+ switch (real_decl_type(darg->type)->type) {
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ psi_to_double(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
+ break;
+ case PSI_T_INT8:
+ case PSI_T_UINT8:
+ if (darg->var->pointer_level) {
+ psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
+ break;
+ }
+ /* no break */
+ case PSI_T_INT16:
+ case PSI_T_UINT16:
+ case PSI_T_INT32:
+ case PSI_T_UINT32:
+ case PSI_T_INT64:
+ case PSI_T_UINT64:
+ psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
+ break;
+ case PSI_T_STRUCT:
+ psi_to_array(&ztmp, real_decl_type(darg->type)->type, &tmp_ptr, darg->var);
+ break;
+ default:
+ printf("t=%d\n", real_decl_type(darg->type)->type);
+ abort();
+ }
+ add_assoc_zval(return_value, darg->var->name, &ztmp);
+ }
+ return;
+ }
+ ret_val = deref_impl_val(ret_val, var);
+ for (i = 0; i < var->arg->var->array_size; ++i) {
+ impl_val *ptr = iterate(ret_val, t, i, &tmp);
+
+ 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);
+ }
+}