b36eb5ffe879086a52b20eab217f74dcada4cf7f
[m6w6/ext-psi] / src / marshal.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include "data.h"
28 #include "calc.h"
29
30 #include "php.h"
31 #include "php_psi.h"
32
33 #include "Zend/zend_interfaces.h"
34 #include "ext/spl/spl_iterators.h"
35
36 zend_long psi_zval_count(zval *zvalue)
37 {
38 /* mimic PHP count() */
39 zend_long count;
40 zval retval;
41
42 switch (Z_TYPE_P(zvalue)) {
43 default:
44 count = 1;
45 break;
46 case IS_NULL:
47 count = 0;
48 break;
49 case IS_ARRAY:
50 count = zend_array_count(Z_ARRVAL_P(zvalue));
51 break;
52 case IS_OBJECT:
53 count = 1;
54 if (Z_OBJ_HT_P(zvalue)->count_elements) {
55 if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) {
56 break;
57 }
58 }
59
60 if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
61 zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval);
62 if (Z_TYPE(retval) != IS_UNDEF) {
63 count = zval_get_long(&retval);
64 zval_ptr_dtor(&retval);
65 }
66 }
67 break;
68 }
69
70 return count;
71 }
72
73 int psi_internal_type(struct psi_impl_type *type)
74 {
75 switch (type->type) {
76 case PSI_T_BOOL:
77 return _IS_BOOL;
78 case PSI_T_INT:
79 return IS_LONG;
80 case PSI_T_FLOAT:
81 case PSI_T_DOUBLE:
82 return IS_DOUBLE;
83 case PSI_T_STRING:
84 return IS_STRING;
85 case PSI_T_ARRAY:
86 return IS_ARRAY;
87 default:
88 return 0;
89 }
90 }
91
92 zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
93 {
94 size_t i = 0, argc = psi_plist_count(impl->func->args);
95 zend_internal_arg_info *aip;
96 zend_internal_function_info *fi;
97 struct psi_impl_arg *iarg;
98
99 aip = calloc(argc + 1 + !!impl->func->vararg, sizeof(*aip));
100
101 fi = (zend_internal_function_info *) &aip[0];
102 #ifdef ZEND_TYPE_ENCODE
103 fi->type = ZEND_TYPE_ENCODE(psi_internal_type(impl->func->return_type), 1);
104 #else
105 fi->allow_null = 1;
106 fi->type_hint = psi_internal_type(impl->func->return_type);
107 #endif
108 fi->required_num_args = psi_impl_num_min_args(impl);
109 fi->return_reference = impl->func->return_reference;
110
111 if (impl->func->vararg) {
112 struct psi_impl_arg *vararg = impl->func->vararg;
113 zend_internal_arg_info *ai = &aip[argc];
114
115 ai->name = vararg->var->name;
116 #ifdef ZEND_TYPE_ENCODE
117 ai->type = ZEND_TYPE_ENCODE(psi_internal_type(vararg->type), 1);
118 #else
119 ai->allow_null = 1;
120 ai->type_hint = psi_internal_type(vararg->type);
121 #endif
122 if (vararg->var->reference) {
123 ai->pass_by_reference = 1;
124 }
125 ai->is_variadic = 1;
126 }
127
128 while (psi_plist_get(impl->func->args, i++, &iarg)) {
129 zend_internal_arg_info *ai = &aip[i];
130
131 ai->name = iarg->var->name;
132 #ifdef ZEND_TYPE_ENCODE
133 ai->type = ZEND_TYPE_ENCODE(psi_internal_type(iarg->type), 1);
134 #else
135 ai->allow_null = 1;
136 ai->type_hint = psi_internal_type(iarg->type);
137 #endif
138 if (iarg->var->reference) {
139 ai->pass_by_reference = 1;
140 }
141 }
142
143 return aip;
144 }
145
146 /*
147 * return void(dvar)
148 */
149 void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
150 {
151 RETVAL_NULL();
152 }
153
154 /*
155 * ?
156 */
157 impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
158 {
159 return tmp;
160 }
161
162 /*
163 * set $ivar = zval(dvar)
164 */
165 void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) {
166 RETVAL_ZVAL(ret_val->ptr, 1, 0);
167 }
168
169 /*
170 * let dvar = zval($ivar)
171 */
172 impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
173 {
174 *to_free = tmp->ptr = emalloc(sizeof(zval));
175 ZVAL_COPY_VALUE(tmp->ptr, zvalue);
176 return tmp;
177 }
178
179 /*
180 * return to_bool(dvar)
181 */
182 void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
183 {
184 psi_set_to_int(return_value, set, ret_val, frame);
185 convert_to_boolean(return_value);
186 }
187
188 static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_bool boolval) {
189 switch (real_type) {
190 case PSI_T_INT8: tmp->i8 = boolval; break;
191 case PSI_T_UINT8: tmp->u8 = boolval; break;
192 case PSI_T_INT16: tmp->i16 = boolval; break;
193 case PSI_T_UINT16: tmp->u16 = boolval; break;
194 case PSI_T_INT32: tmp->i32 = boolval; break;
195 case PSI_T_UINT32: tmp->u32 = boolval; break;
196 case PSI_T_INT64: tmp->i64 = boolval; break;
197 case PSI_T_UINT64: tmp->u64 = boolval; break;
198 case PSI_T_FLOAT: tmp->fval = boolval; break;
199 case PSI_T_DOUBLE: tmp->dval = boolval; break;
200 #ifdef HAVE_LONG_DOUBLE
201 case PSI_T_LONG_DOUBLE: tmp->ldval = boolval; break;
202 #endif
203 EMPTY_SWITCH_DEFAULT_CASE();
204 }
205 return tmp;
206 }
207
208 /*
209 * let dvar = boolval($ivar)
210 */
211 impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
212 {
213 zend_bool boolval;
214 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
215
216 if (ival && impl_type == PSI_T_BOOL) {
217 boolval = ival->zend.bval;
218 } else {
219 boolval = zend_is_true(zvalue);
220 }
221
222 return psi_val_boolval(tmp, real_type, boolval);
223 }
224
225 # define RETVAL_LONG_U64(V) \
226 if (V > ZEND_LONG_MAX) { \
227 char d[24] = {0}; \
228 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
229 } else { \
230 RETVAL_LONG(V); \
231 }
232
233 /*
234 * set $ivar = to_int(*dvar)
235 */
236 void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
237 {
238 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
239 token_t t = psi_decl_type_get_real(var->arg->type)->type;
240 impl_val *v = deref_impl_val(ret_val, var);
241
242 switch (t) {
243 case PSI_T_INT8: RETVAL_LONG(v->i8); break;
244 case PSI_T_UINT8: RETVAL_LONG(v->u8); break;
245 case PSI_T_INT16: RETVAL_LONG(v->i16); break;
246 case PSI_T_UINT16: RETVAL_LONG(v->u16); break;
247 case PSI_T_INT32: RETVAL_LONG(v->i32); break;
248 case PSI_T_UINT32: RETVAL_LONG(v->u32); break;
249 case PSI_T_INT64: RETVAL_LONG(v->i64); break;
250 case PSI_T_UINT64: RETVAL_LONG_U64(v->u64); break;
251 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
252 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
253 #ifdef HAVE_LONG_DOUBLE
254 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
255 #endif
256 EMPTY_SWITCH_DEFAULT_CASE();
257 }
258
259 convert_to_long(return_value);
260 }
261
262 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
263 switch (real_type) {
264 case PSI_T_INT8: tmp->i8 = intval; break;
265 case PSI_T_UINT8: tmp->u8 = intval; break;
266 case PSI_T_INT16: tmp->i16 = intval; break;
267 case PSI_T_UINT16: tmp->u16 = intval; break;
268 case PSI_T_INT32: tmp->i32 = intval; break;
269 case PSI_T_UINT32: tmp->u32 = intval; break;
270 case PSI_T_INT64: tmp->i64 = intval; break;
271 case PSI_T_UINT64: tmp->u64 = intval; break;
272 case PSI_T_INT: tmp->ival = intval; break;
273 case PSI_T_LONG: tmp->lval = intval; break;
274 case PSI_T_FLOAT: tmp->fval = intval; break;
275 case PSI_T_DOUBLE: tmp->dval = intval; break;
276 #ifdef HAVE_LONG_DOUBLE
277 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
278 #endif
279 EMPTY_SWITCH_DEFAULT_CASE();
280 }
281
282 return tmp;
283 }
284
285 /*
286 * let dvar = intval($ivar)
287 */
288 impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
289 {
290 zend_long intval;
291 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
292
293 if (ival && impl_type == PSI_T_INT) {
294 intval = ival->zend.lval;
295 } else {
296 intval = zval_get_long(zvalue);
297 }
298
299 return psi_val_intval(tmp, real_type, intval);
300 }
301
302 /*
303 * set $ivar = to_float(dvar)
304 */
305 void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
306 {
307 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
308 token_t t = psi_decl_type_get_real(var->arg->type)->type;
309 impl_val *v = deref_impl_val(ret_val, var);
310
311 switch (t) {
312 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
313 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
314 #ifdef HAVE_LONG_DOUBLE
315 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
316 #endif
317 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
318 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
319 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
320 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
321 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
322 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
323 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
324 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
325 EMPTY_SWITCH_DEFAULT_CASE();
326 }
327 }
328
329 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
330 switch (real_type) {
331 case PSI_T_INT8: tmp->i8 = floatval; break;
332 case PSI_T_UINT8: tmp->u8 = floatval; break;
333 case PSI_T_INT16: tmp->i16 = floatval; break;
334 case PSI_T_UINT16: tmp->u16 = floatval; break;
335 case PSI_T_INT32: tmp->i32 = floatval; break;
336 case PSI_T_UINT32: tmp->u32 = floatval; break;
337 case PSI_T_INT64: tmp->i64 = floatval; break;
338 case PSI_T_UINT64: tmp->u64 = floatval; break;
339 case PSI_T_FLOAT: tmp->fval = floatval; break;
340 case PSI_T_DOUBLE: tmp->dval = floatval; break;
341 #ifdef HAVE_LONG_DOUBLE
342 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
343 #endif
344 EMPTY_SWITCH_DEFAULT_CASE();
345 }
346
347 return tmp;
348 }
349
350 /*
351 * let dvar = floatval($ivar)
352 */
353 impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
354 {
355 double floatval;
356 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
357
358 if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
359 floatval = ival->dval;
360 } else {
361 floatval = zval_get_double(zvalue);
362 }
363
364 return psi_val_floatval(tmp, real_type, floatval);
365 }
366
367 /*
368 * set $ivar = to_string(dvar)
369 */
370 void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
371 {
372 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
373 impl_val *ptr = deref_impl_val(ret_val, var);
374 char *str;
375
376 if (var->arg->var->array_size) {
377 str = (char *) ptr;
378 } else {
379 str = ptr->ptr;
380 }
381
382 if (str) {
383 RETVAL_STRING(str);
384 } else {
385 RETVAL_EMPTY_STRING();
386 }
387 }
388
389 /*
390 * set $ivar = to_string(dvar, num_exp)
391 */
392 void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
393 {
394 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
395 char *str = deref_impl_val(ret_val, var)->ptr;
396
397 if (str) {
398 struct psi_set_exp *sub_exp;
399
400 psi_plist_get(set->inner, 0, &sub_exp);
401 RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame, NULL));
402 } else {
403 RETVAL_EMPTY_STRING();
404 }
405 }
406
407 /*
408 * let dvar = strval($ivar)
409 */
410 impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
411 {
412 if (ival && impl_type == PSI_T_STRING) {
413 if (ival->zend.str) {
414 tmp->ptr = ival->zend.str->val;
415 } else {
416 tmp->ptr = "";
417 }
418 } else {
419 zend_string *zs = zval_get_string(zvalue);
420 tmp->ptr = estrdup(zs->val);
421 *to_free = tmp->ptr;
422 zend_string_release(zs);
423 }
424
425 return tmp;
426 }
427
428 /*
429 * let dvar = pathval($ivar)
430 */
431 impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
432 {
433 tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
434 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
435 efree(tmp->ptr);
436 tmp->ptr = NULL;
437 return *to_free = NULL;
438 }
439 return tmp;
440 }
441
442 /*
443 * let dvar = strlen($ivar)
444 */
445 impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
446 {
447 if (ival && impl_type == PSI_T_STRING) {
448 if (ival->zend.str) {
449 tmp->lval = ival->zend.str->len;
450 } else {
451 tmp->lval = 0;
452 }
453 } else {
454 zend_string *zs = zval_get_string(zvalue);
455 tmp->lval = zs->len;
456 zend_string_release(zs);
457 }
458
459 return tmp;
460 }
461
462 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
463 {
464 memset(tmp, 0, sizeof(*tmp));
465 memcpy(tmp, ((char *) val) + size * i, size);
466 return tmp;
467 }
468
469 /*
470 * set $ivar = to_array(dvar,
471 * $foo = to_int(d_foo),
472 * $bar = to_string(d_bar),
473 * $baz = to_array(*d_next, ...)
474 */
475 void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
476 set->outer->data.func->handler(return_value, set, r_val, frame);
477 }
478
479 /*
480 * set $ivar = to_array(dvar, to_string(*dvar));
481 */
482 void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
483 {
484 struct psi_set_exp *sub_exp;
485 struct psi_decl_var *var;
486 impl_val *ret_val;
487 char *ptr;
488 size_t size;
489
490 array_init(return_value);
491
492 var = psi_set_exp_get_decl_var(set);
493 ret_val = deref_impl_val(r_val, var);
494 if ((intptr_t) ret_val <= (intptr_t) 0) {
495 return;
496 }
497
498 psi_plist_get(set->inner, 0, &sub_exp);
499
500 size = psi_decl_arg_get_size(var->arg);
501 for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
502 zval ele;
503
504 ZVAL_NULL(&ele);
505 sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
506 add_next_index_zval(return_value, &ele);
507 }
508 }
509
510 /*
511 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
512 */
513 void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
514 {
515 struct psi_set_exp *sub_exp;
516 struct psi_decl_var *var;
517 impl_val *ret_val;
518 char *ptr;
519 size_t size;
520 zend_long count;
521
522 array_init(return_value);
523
524 var = psi_set_exp_get_decl_var(set);
525 ret_val = deref_impl_val(r_val, var);
526 if ((intptr_t) ret_val <= (intptr_t) 0) {
527 return;
528 }
529
530 psi_plist_get(set->inner, 0, &sub_exp);
531 count = psi_long_num_exp(sub_exp->data.num, frame, NULL);
532 psi_plist_get(set->inner, 1, &sub_exp);
533
534 for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
535 size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
536 zval ele;
537
538 ZVAL_NULL(&ele);
539 sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
540 add_next_index_zval(return_value, &ele);
541 }
542 }
543
544 #include "call.h"
545
546 /*
547 * set $ivar = to_array(dvar,
548 * $foo = to_int(d_foo),
549 * $bar = to_string(d_bar));
550 */
551 void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
552 {
553 struct psi_set_exp *sub_exp;
554 struct psi_decl_var *var;
555 impl_val *ret_val;
556 size_t i = 0;
557
558 array_init(return_value);
559
560 var = psi_set_exp_get_decl_var(set);
561 ret_val = deref_impl_val(r_val, var);
562 if ((intptr_t) ret_val <= (intptr_t) 0) {
563 return;
564 }
565
566 while (psi_plist_get(set->inner, i++, &sub_exp)) {
567 zval ele;
568 struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
569 struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
570 struct psi_call_frame_symbol *sym;
571
572 sym = psi_call_frame_fetch_symbol(frame, dvar);
573 sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
574
575 ZVAL_NULL(&ele);
576 psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
577 add_assoc_zval(return_value, ivar->name + 1, &ele);
578 }
579 }
580
581 //impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
582 //{
583 // decl_type *real = real_decl_type(spec);
584 // HashTable *arr;
585 // zval *zv;
586 // size_t i, sz;
587 // decl_arg tmp_arg = {0};
588 //
589 // if (impl_type != PSI_T_ARRAY) {
590 // SEPARATE_ARG_IF_REF(zvalue);
591 // convert_to_array(zvalue);
592 // }
593 // arr = HASH_OF(zvalue);
594 //
595 // switch (real->type) {
596 // case PSI_T_STRUCT:
597 // *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
598 // break;
599 // case PSI_T_UNION:
600 // *to_free = tmp = psi_array_to_union(real->real.unn, arr);
601 // break;
602 // default:
603 // sz = psi_t_size(real->type);
604 // tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
605 // tmp_arg.type = spec;
606 // tmp_arg.var = spec_var;
607 // ZEND_HASH_FOREACH_VAL_IND(arr, zv)
608 // {
609 // void *ptr = ((char *) tmp) + (i++ * sz);
610 // psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
611 // }
612 // ZEND_HASH_FOREACH_END();
613 // }
614 //
615 // return tmp;
616 //}
617
618 /*
619 * let dvar = count($ivar)
620 */
621 impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
622 {
623 return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
624 }
625
626 /*
627 * set $ivar = to_object(dvar)
628 */
629 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
630 {
631 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
632 impl_val *ret_val = deref_impl_val(r_val, var);
633
634 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
635 object_init_ex(return_value, psi_object_get_class_entry());
636 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
637 } else {
638 RETVAL_NULL();
639 }
640 }
641
642 /*
643 * let dvar = objval($ivar)
644 */
645 impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
646 {
647 psi_object *obj;
648
649 if (Z_TYPE_P(zvalue) != IS_OBJECT
650 || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) {
651 return NULL;
652 }
653
654 obj = PSI_OBJ(zvalue, NULL);
655 tmp->ptr = obj->data;
656
657 return tmp;
658 }
659