raising the head after a three-weeks refactoring
[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 fi->allow_null = 1;
103 fi->required_num_args = psi_impl_num_min_args(impl);
104 fi->return_reference = impl->func->return_reference;
105 fi->type_hint = psi_internal_type(impl->func->return_type);
106
107 if (impl->func->vararg) {
108 struct psi_impl_arg *vararg = impl->func->vararg;
109 zend_internal_arg_info *ai = &aip[argc];
110
111 ai->name = vararg->var->name;
112 ai->allow_null = 1;
113 ai->type_hint = psi_internal_type(vararg->type);
114 if (vararg->var->reference) {
115 ai->pass_by_reference = 1;
116 }
117 ai->is_variadic = 1;
118 }
119
120 while (psi_plist_get(impl->func->args, i++, &iarg)) {
121 zend_internal_arg_info *ai = &aip[i];
122
123 ai->name = iarg->var->name;
124 ai->type_hint = psi_internal_type(iarg->type);
125 if (iarg->var->reference) {
126 ai->pass_by_reference = 1;
127 }
128 /* FIXME: if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) */
129 ai->allow_null = 1;
130 }
131
132 return aip;
133 }
134
135 /*
136 * return void(dvar)
137 */
138 void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
139 {
140 RETVAL_NULL();
141 }
142
143 /*
144 * ?
145 */
146 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)
147 {
148 return tmp;
149 }
150
151 /*
152 * set $ivar = zval(dvar)
153 */
154 void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) {
155 RETVAL_ZVAL(ret_val->ptr, 1, 0);
156 }
157
158 /*
159 * let dvar = zval($ivar)
160 */
161 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)
162 {
163 *to_free = tmp->ptr = emalloc(sizeof(zval));
164 ZVAL_COPY_VALUE(tmp->ptr, zvalue);
165 return tmp;
166 }
167
168 /*
169 * return to_bool(dvar)
170 */
171 void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
172 {
173 psi_set_to_int(return_value, set, ret_val, frame);
174 convert_to_boolean(return_value);
175 }
176
177 static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_bool boolval) {
178 switch (real_type) {
179 case PSI_T_INT8: tmp->i8 = boolval; break;
180 case PSI_T_UINT8: tmp->u8 = boolval; break;
181 case PSI_T_INT16: tmp->i16 = boolval; break;
182 case PSI_T_UINT16: tmp->u16 = boolval; break;
183 case PSI_T_INT32: tmp->i32 = boolval; break;
184 case PSI_T_UINT32: tmp->u32 = boolval; break;
185 case PSI_T_INT64: tmp->i64 = boolval; break;
186 case PSI_T_UINT64: tmp->u64 = boolval; break;
187 case PSI_T_FLOAT: tmp->fval = boolval; break;
188 case PSI_T_DOUBLE: tmp->dval = boolval; break;
189 #ifdef HAVE_LONG_DOUBLE
190 case PSI_T_LONG_DOUBLE: tmp->ldval = boolval; break;
191 #endif
192 EMPTY_SWITCH_DEFAULT_CASE();
193 }
194 return tmp;
195 }
196
197 /*
198 * let dvar = boolval($ivar)
199 */
200 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)
201 {
202 zend_bool boolval;
203 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
204
205 if (ival && impl_type == PSI_T_BOOL) {
206 boolval = ival->zend.bval;
207 } else {
208 boolval = zend_is_true(zvalue);
209 }
210
211 return psi_val_boolval(tmp, real_type, boolval);
212 }
213
214 # define RETVAL_LONG_U64(V) \
215 if (V > ZEND_LONG_MAX) { \
216 char d[24] = {0}; \
217 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
218 } else { \
219 RETVAL_LONG(V); \
220 }
221
222 /*
223 * set $ivar = to_int(*dvar)
224 */
225 void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
226 {
227 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
228 token_t t = psi_decl_type_get_real(var->arg->type)->type;
229 impl_val *v = deref_impl_val(ret_val, var);
230
231 switch (t) {
232 case PSI_T_INT8: RETVAL_LONG(v->i8); break;
233 case PSI_T_UINT8: RETVAL_LONG(v->u8); break;
234 case PSI_T_INT16: RETVAL_LONG(v->i16); break;
235 case PSI_T_UINT16: RETVAL_LONG(v->u16); break;
236 case PSI_T_INT32: RETVAL_LONG(v->i32); break;
237 case PSI_T_UINT32: RETVAL_LONG(v->u32); break;
238 case PSI_T_INT64: RETVAL_LONG(v->i64); break;
239 case PSI_T_UINT64: RETVAL_LONG_U64(v->u64); break;
240 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
241 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
242 #ifdef HAVE_LONG_DOUBLE
243 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
244 #endif
245 EMPTY_SWITCH_DEFAULT_CASE();
246 }
247
248 convert_to_long(return_value);
249 }
250
251 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
252 switch (real_type) {
253 case PSI_T_INT8: tmp->i8 = intval; break;
254 case PSI_T_UINT8: tmp->u8 = intval; break;
255 case PSI_T_INT16: tmp->i16 = intval; break;
256 case PSI_T_UINT16: tmp->u16 = intval; break;
257 case PSI_T_INT32: tmp->i32 = intval; break;
258 case PSI_T_UINT32: tmp->u32 = intval; break;
259 case PSI_T_INT64: tmp->i64 = intval; break;
260 case PSI_T_UINT64: tmp->u64 = intval; break;
261 case PSI_T_INT: tmp->ival = intval; break;
262 case PSI_T_LONG: tmp->lval = intval; break;
263 case PSI_T_FLOAT: tmp->fval = intval; break;
264 case PSI_T_DOUBLE: tmp->dval = intval; break;
265 #ifdef HAVE_LONG_DOUBLE
266 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
267 #endif
268 EMPTY_SWITCH_DEFAULT_CASE();
269 }
270
271 return tmp;
272 }
273
274 /*
275 * let dvar = intval($ivar)
276 */
277 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)
278 {
279 zend_long intval;
280 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
281
282 if (ival && impl_type == PSI_T_INT) {
283 intval = ival->zend.lval;
284 } else {
285 intval = zval_get_long(zvalue);
286 }
287
288 return psi_val_intval(tmp, real_type, intval);
289 }
290
291 /*
292 * set $ivar = to_float(dvar)
293 */
294 void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
295 {
296 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
297 token_t t = psi_decl_type_get_real(var->arg->type)->type;
298 impl_val *v = deref_impl_val(ret_val, var);
299
300 switch (t) {
301 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
302 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
303 #ifdef HAVE_LONG_DOUBLE
304 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
305 #endif
306 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
307 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
308 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
309 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
310 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
311 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
312 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
313 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
314 EMPTY_SWITCH_DEFAULT_CASE();
315 }
316 }
317
318 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
319 switch (real_type) {
320 case PSI_T_INT8: tmp->i8 = floatval; break;
321 case PSI_T_UINT8: tmp->u8 = floatval; break;
322 case PSI_T_INT16: tmp->i16 = floatval; break;
323 case PSI_T_UINT16: tmp->u16 = floatval; break;
324 case PSI_T_INT32: tmp->i32 = floatval; break;
325 case PSI_T_UINT32: tmp->u32 = floatval; break;
326 case PSI_T_INT64: tmp->i64 = floatval; break;
327 case PSI_T_UINT64: tmp->u64 = floatval; break;
328 case PSI_T_FLOAT: tmp->fval = floatval; break;
329 case PSI_T_DOUBLE: tmp->dval = floatval; break;
330 #ifdef HAVE_LONG_DOUBLE
331 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
332 #endif
333 EMPTY_SWITCH_DEFAULT_CASE();
334 }
335
336 return tmp;
337 }
338
339 /*
340 * let dvar = floatval($ivar)
341 */
342 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)
343 {
344 double floatval;
345 token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
346
347 if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
348 floatval = ival->dval;
349 } else {
350 floatval = zval_get_double(zvalue);
351 }
352
353 return psi_val_floatval(tmp, real_type, floatval);
354 }
355
356 /*
357 * set $ivar = to_string(dvar)
358 */
359 void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
360 {
361 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
362 impl_val *ptr = deref_impl_val(ret_val, var);
363 char *str;
364
365 if (var->arg->var->array_size) {
366 str = (char *) ptr;
367 } else {
368 str = ptr->ptr;
369 }
370
371 if (str) {
372 RETVAL_STRING(str);
373 } else {
374 RETVAL_EMPTY_STRING();
375 }
376 }
377
378 /*
379 * set $ivar = to_string(dvar, num_exp)
380 */
381 void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
382 {
383 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
384 char *str = deref_impl_val(ret_val, var)->ptr;
385
386 if (str) {
387 struct psi_set_exp *sub_exp;
388
389 psi_plist_get(set->inner, 0, &sub_exp);
390 RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame));
391 } else {
392 RETVAL_EMPTY_STRING();
393 }
394 }
395
396 /*
397 * let dvar = strval($ivar)
398 */
399 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)
400 {
401 if (ival && impl_type == PSI_T_STRING) {
402 if (ival->zend.str) {
403 tmp->ptr = ival->zend.str->val;
404 } else {
405 tmp->ptr = "";
406 }
407 } else if (0 && Z_TYPE_P(zvalue) == IS_STRING) {
408 tmp->ptr = Z_STRVAL_P(zvalue);
409 } else {
410 zend_string *zs = zval_get_string(zvalue);
411 tmp->ptr = estrdup(zs->val);
412 *to_free = tmp->ptr;
413 zend_string_release(zs);
414 }
415
416 return tmp;
417 }
418
419 /*
420 * let dvar = pathval($ivar)
421 */
422 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)
423 {
424 tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
425 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
426 efree(tmp->ptr);
427 tmp->ptr = NULL;
428 return *to_free = NULL;
429 }
430 return tmp;
431 }
432
433 /*
434 * let dvar = strlen($ivar)
435 */
436 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)
437 {
438 if (ival && impl_type == PSI_T_STRING) {
439 if (ival->zend.str) {
440 tmp->lval = ival->zend.str->len;
441 } else {
442 tmp->lval = 0;
443 }
444 } else {
445 zend_string *zs = zval_get_string(zvalue);
446 tmp->lval = zs->len;
447 zend_string_release(zs);
448 }
449
450 return tmp;
451 }
452
453 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
454 {
455 memset(tmp, 0, sizeof(*tmp));
456 memcpy(tmp, ((char *) val) + size * i, size);
457 return tmp;
458 }
459
460 /*
461 * set $ivar = to_array(dvar,
462 * $foo = to_int(d_foo),
463 * $bar = to_string(d_bar),
464 * $baz = to_array(*d_next, ...)
465 */
466 void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
467 set->outer->data.func->handler(return_value, set, r_val, frame);
468 }
469
470 /*
471 * set $ivar = to_array(dvar, to_string(*dvar));
472 */
473 void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
474 {
475 struct psi_set_exp *sub_exp;
476 struct psi_decl_var *var;
477 impl_val *ret_val;
478 char *ptr;
479 size_t size;
480
481 array_init(return_value);
482
483 var = psi_set_exp_get_decl_var(set);
484 ret_val = deref_impl_val(r_val, var);
485 if ((intptr_t) ret_val <= (intptr_t) 0) {
486 return;
487 }
488
489 psi_plist_get(set->inner, 0, &sub_exp);
490
491 size = psi_decl_arg_get_size(var->arg);
492 for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
493 zval ele;
494
495 ZVAL_NULL(&ele);
496 sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
497 add_next_index_zval(return_value, &ele);
498 }
499 }
500
501 /*
502 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
503 */
504 void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
505 {
506 struct psi_set_exp *sub_exp;
507 struct psi_decl_var *var;
508 impl_val *ret_val;
509 char *ptr;
510 size_t size;
511 zend_long count;
512
513 array_init(return_value);
514
515 var = psi_set_exp_get_decl_var(set);
516 ret_val = deref_impl_val(r_val, var);
517 if ((intptr_t) ret_val <= (intptr_t) 0) {
518 return;
519 }
520
521 psi_plist_get(set->inner, 0, &sub_exp);
522 count = psi_long_num_exp(sub_exp->data.num, frame);
523 psi_plist_get(set->inner, 1, &sub_exp);
524
525 for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
526 size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
527 zval ele;
528
529 ZVAL_NULL(&ele);
530 sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
531 add_next_index_zval(return_value, &ele);
532 }
533 }
534
535 #include "call.h"
536
537 /*
538 * set $ivar = to_array(dvar,
539 * $foo = to_int(d_foo),
540 * $bar = to_string(d_bar));
541 */
542 void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
543 {
544 struct psi_set_exp *sub_exp;
545 struct psi_decl_var *var;
546 impl_val *ret_val;
547 size_t i = 0;
548
549 array_init(return_value);
550
551 var = psi_set_exp_get_decl_var(set);
552 ret_val = deref_impl_val(r_val, var);
553 if ((intptr_t) ret_val <= (intptr_t) 0) {
554 return;
555 }
556
557 while (psi_plist_get(set->inner, i++, &sub_exp)) {
558 zval ele;
559 struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
560 struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
561 struct psi_call_frame_symbol *sym;
562
563 sym = psi_call_frame_fetch_symbol(frame, dvar);
564 sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
565
566 ZVAL_NULL(&ele);
567 psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
568 add_assoc_zval(return_value, ivar->name + 1, &ele);
569 }
570 }
571
572 //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)
573 //{
574 // decl_type *real = real_decl_type(spec);
575 // HashTable *arr;
576 // zval *zv;
577 // size_t i, sz;
578 // decl_arg tmp_arg = {0};
579 //
580 // if (impl_type != PSI_T_ARRAY) {
581 // SEPARATE_ARG_IF_REF(zvalue);
582 // convert_to_array(zvalue);
583 // }
584 // arr = HASH_OF(zvalue);
585 //
586 // switch (real->type) {
587 // case PSI_T_STRUCT:
588 // *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
589 // break;
590 // case PSI_T_UNION:
591 // *to_free = tmp = psi_array_to_union(real->real.unn, arr);
592 // break;
593 // default:
594 // sz = psi_t_size(real->type);
595 // tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
596 // tmp_arg.type = spec;
597 // tmp_arg.var = spec_var;
598 // ZEND_HASH_FOREACH_VAL_IND(arr, zv)
599 // {
600 // void *ptr = ((char *) tmp) + (i++ * sz);
601 // psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
602 // }
603 // ZEND_HASH_FOREACH_END();
604 // }
605 //
606 // return tmp;
607 //}
608
609 /*
610 * let dvar = count($ivar)
611 */
612 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)
613 {
614 return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
615 }
616
617 /*
618 * set $ivar = to_object(dvar)
619 */
620 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
621 {
622 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
623 impl_val *ret_val = deref_impl_val(r_val, var);
624
625 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
626 object_init_ex(return_value, psi_object_get_class_entry());
627 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
628 } else {
629 RETVAL_NULL();
630 }
631 }
632
633 /*
634 * let dvar = objval($ivar)
635 */
636 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)
637 {
638 psi_object *obj;
639
640 if (Z_TYPE_P(zvalue) != IS_OBJECT
641 || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) {
642 return NULL;
643 }
644
645 obj = PSI_OBJ(zvalue, NULL);
646 tmp->ptr = obj->data;
647
648 return tmp;
649 }
650