PHP 8 compatibility
[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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31 #include "data.h"
32 #include "calc.h"
33
34 #include "php.h"
35 #include "php_psi.h"
36
37 #include "Zend/zend_interfaces.h"
38 #include "ext/spl/spl_iterators.h"
39
40 zend_long psi_zval_count(zval *zvalue)
41 {
42 /* mimic PHP count() */
43 zend_long count;
44 zval retval;
45
46 switch (Z_TYPE_P(zvalue)) {
47 default:
48 count = 1;
49 break;
50 case IS_NULL:
51 count = 0;
52 break;
53 case IS_ARRAY:
54 count = zend_array_count(Z_ARRVAL_P(zvalue));
55 break;
56 case IS_OBJECT:
57 count = 1;
58 if (Z_OBJ_HT_P(zvalue)->count_elements) {
59 if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(Z_OBJ_P(zvalue), &count)) {
60 break;
61 }
62 }
63
64 if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
65 zend_call_method_with_0_params(Z_OBJ_P(zvalue), NULL, NULL, "count", &retval);
66 if (Z_TYPE(retval) != IS_UNDEF) {
67 count = zval_get_long(&retval);
68 zval_ptr_dtor(&retval);
69 }
70 }
71 break;
72 }
73
74 return count;
75 }
76
77 int psi_internal_type(struct psi_impl_type *type)
78 {
79 switch (type->type) {
80 case PSI_T_BOOL:
81 return _IS_BOOL;
82 case PSI_T_INT:
83 return IS_LONG;
84 case PSI_T_FLOAT:
85 case PSI_T_DOUBLE:
86 return IS_DOUBLE;
87 case PSI_T_STRING:
88 return IS_STRING;
89 case PSI_T_ARRAY:
90 return IS_ARRAY;
91 default:
92 return 0;
93 }
94 }
95
96 zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
97 {
98 size_t i = 0, argc = psi_plist_count(impl->func->args);
99 zend_internal_arg_info *aip;
100 zend_internal_function_info *fi;
101 struct psi_impl_arg *iarg;
102 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));
103
104 aip = pecalloc(argc + 1 + !!impl->func->vararg, sizeof(*aip), 1);
105
106 fi = (zend_internal_function_info *) &aip[0];
107 fi->required_num_args = psi_impl_num_min_args(impl);
108 fi->type = rtyp;
109
110 if (impl->func->vararg) {
111 struct psi_impl_arg *vararg = impl->func->vararg;
112 zend_internal_arg_info *ai = &aip[argc];
113 zend_type atyp = ZEND_TYPE_INIT_CODE(psi_internal_type(vararg->type), 1, _ZEND_ARG_INFO_FLAGS(vararg->var->reference, 1));
114
115 ai->name = &vararg->var->name->val[1];
116 ai->type = atyp;
117 }
118
119 while (psi_plist_get(impl->func->args, i++, &iarg)) {
120 zend_internal_arg_info *ai = &aip[i];
121 zend_type atyp = ZEND_TYPE_INIT_CODE(psi_internal_type(iarg->type), 1, _ZEND_ARG_INFO_FLAGS(iarg->var->reference, 0));
122
123 ai->name = &iarg->var->name->val[1];
124 ai->type = atyp;
125 }
126
127 return aip;
128 }
129
130 /*
131 * return void(dvar)
132 */
133 void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
134 {
135 RETVAL_NULL();
136 }
137
138 /*
139 * ?
140 */
141 impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
142 {
143 return tmp;
144 }
145
146 /*
147 * set $ivar = zval(dvar)
148 */
149 void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) {
150 RETVAL_ZVAL(ret_val->ptr, 1, 0);
151 }
152
153 /*
154 * let dvar = zval($ivar)
155 */
156 impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
157 {
158 *to_free = tmp->ptr = emalloc(sizeof(zval));
159 ZVAL_COPY_VALUE(tmp->ptr, zvalue);
160 return tmp;
161 }
162
163 /*
164 * return to_bool(dvar)
165 */
166 void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
167 {
168 psi_set_to_int(return_value, set, ret_val, frame);
169 convert_to_boolean(return_value);
170 }
171
172 static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_bool boolval) {
173 switch (real_type) {
174 case PSI_T_INT8: tmp->i8 = boolval; break;
175 case PSI_T_UINT8: tmp->u8 = boolval; break;
176 case PSI_T_INT16: tmp->i16 = boolval; break;
177 case PSI_T_UINT16: tmp->u16 = boolval; break;
178 case PSI_T_INT32: tmp->i32 = boolval; break;
179 case PSI_T_UINT32: tmp->u32 = boolval; break;
180 case PSI_T_INT64: tmp->i64 = boolval; break;
181 case PSI_T_UINT64: tmp->u64 = boolval; break;
182 #ifdef HAVE_INT128
183 case PSI_T_INT128: tmp->i128 = boolval; break;
184 case PSI_T_UINT128: tmp->u128 = boolval; break;
185 #endif
186 case PSI_T_FLOAT: tmp->fval = boolval; break;
187 case PSI_T_DOUBLE: tmp->dval = boolval; break;
188 #ifdef HAVE_LONG_DOUBLE
189 case PSI_T_LONG_DOUBLE: tmp->ldval = boolval; break;
190 #endif
191 EMPTY_SWITCH_DEFAULT_CASE();
192 }
193 return tmp;
194 }
195
196 /*
197 * let dvar = boolval($ivar)
198 */
199 impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
200 {
201 zend_bool boolval;
202 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8;
203
204 if (ival && impl_type == PSI_T_BOOL) {
205 boolval = ival->zend.bval;
206 } else {
207 boolval = zend_is_true(zvalue);
208 }
209
210 return psi_val_boolval(tmp, real_type, boolval);
211 }
212
213 /*
214 * set $ivar = to_int(*dvar)
215 */
216 void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
217 {
218 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
219 token_t t = psi_decl_type_get_real(var->arg->type)->type;
220 impl_val *v = deref_impl_val(ret_val, var);
221
222 switch (t) {
223 case PSI_T_INT8: RETVAL_LONG(v->i8); break;
224 case PSI_T_UINT8: RETVAL_LONG(v->u8); break;
225 case PSI_T_INT16: RETVAL_LONG(v->i16); break;
226 case PSI_T_UINT16: RETVAL_LONG(v->u16); break;
227 case PSI_T_ENUM:
228 case PSI_T_INT32: RETVAL_LONG(v->i32); break;
229 case PSI_T_UINT32: RETVAL_LONG(v->u32); break;
230 case PSI_T_INT64: RETVAL_LONG(v->i64); break;
231 case PSI_T_UINT64: RETVAL_LONG_DOUBLE_STR(v->u64,); break;
232 #ifdef HAVE_INT128
233 case PSI_T_INT128: RETVAL_LONG_DOUBLE_STR(v->i128, is_signed=true); break;
234 case PSI_T_UINT128: RETVAL_LONG_DOUBLE_STR(v->u128,); break;
235 #endif
236 case PSI_T_FLOAT:
237 RETVAL_DOUBLE((double) v->fval);
238 convert_to_long(return_value);
239 break;
240 case PSI_T_DOUBLE:
241 RETVAL_DOUBLE(v->dval);
242 convert_to_long(return_value);
243 break;
244 #ifdef HAVE_LONG_DOUBLE
245 case PSI_T_LONG_DOUBLE:
246 RETVAL_DOUBLE((double) v->ldval);
247 convert_to_long(return_value);
248 break;
249 #endif
250 EMPTY_SWITCH_DEFAULT_CASE();
251 }
252 }
253
254 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
255 switch (real_type) {
256 case PSI_T_INT8: tmp->i8 = intval; break;
257 case PSI_T_UINT8: tmp->u8 = intval; break;
258 case PSI_T_INT16: tmp->i16 = intval; break;
259 case PSI_T_UINT16: tmp->u16 = intval; break;
260 case PSI_T_ENUM:
261 case PSI_T_INT32: tmp->i32 = intval; break;
262 case PSI_T_UINT32: tmp->u32 = intval; break;
263 case PSI_T_INT64: tmp->i64 = intval; break;
264 case PSI_T_UINT64: tmp->u64 = intval; break;
265 #if HAVE_INT128
266 case PSI_T_INT128: tmp->i128 = intval; break;
267 case PSI_T_UINT128: tmp->u128 = intval; break;
268 #endif
269 case PSI_T_FLOAT: tmp->fval = intval; break;
270 case PSI_T_DOUBLE: tmp->dval = intval; break;
271 #ifdef HAVE_LONG_DOUBLE
272 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
273 #endif
274 EMPTY_SWITCH_DEFAULT_CASE();
275 }
276
277 return tmp;
278 }
279
280 #if HAVE_INT128
281 static void psi_strto_i128(char *ptr, char *end, token_t real_type, impl_val *val) {
282 unsigned __int128 i = 0;
283 bool oct = false, hex = false, sign = false;
284
285 if (*ptr == '+') {
286 ++ptr;
287 } else if (*ptr == '-') {
288 sign = true;
289 ++ptr;
290 } else if (*ptr == '\\') {
291 switch (*++ptr) {
292 case 'x':
293 hex = true;
294 ++ptr;
295 break;
296 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
297 oct = true;
298 break;
299 default:
300 goto fail;
301 }
302 }
303 while (ptr < end) {
304 switch (*ptr) {
305 case '8':case '9':
306 if (oct) {
307 goto fail;
308 }
309 /* no break */
310 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
311 if (oct) {
312 i <<= 3;
313 } else if (hex) {
314 i <<= 4;
315 } else {
316 i *= 10;
317 }
318 i += *ptr - '0';
319 break;
320 case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
321 if (!hex) {
322 goto fail;
323 }
324 i <<= 4;
325 i += 10 + (*ptr - 'a');
326 break;
327 case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
328 if (!hex) {
329 goto fail;
330 }
331 i <<= 4;
332 i += 10 + (*ptr - 'A');
333 break;
334 default:
335 fail:
336 zend_error(E_WARNING, "A non well formed numeric value encountered");
337 goto stop;
338 }
339 ++ptr;
340 }
341
342 stop:
343 if (real_type == PSI_T_UINT128) {
344 if (sign) {
345 val->u128 = -i;
346 } else {
347 val->u128 = i;
348 }
349 } else {
350 if (sign) {
351 val->i128 = -i;
352 } else {
353 val->i128 = i;
354 }
355 }
356 }
357 #endif
358
359 /*
360 * let dvar = intval($ivar)
361 */
362 impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
363 {
364 int64_t intval;
365 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_INT64;
366
367
368 if (ival && impl_type == PSI_T_INT) {
369 intval = ival->zend.lval;
370 #if HAVE_INT128
371 } else if ((real_type == PSI_T_UINT128 || real_type == PSI_T_INT128) &&
372 !((Z_TYPE_P(zvalue) == IS_TRUE || Z_TYPE_P(zvalue) == IS_FALSE || Z_TYPE_P(zvalue) == IS_LONG || Z_TYPE_P(zvalue) == IS_DOUBLE || Z_TYPE_P(zvalue) == IS_NULL))) {
373 zend_string *str = zval_get_string(zvalue);
374 psi_strto_i128(str->val, str->val + str->len, real_type, tmp);
375 zend_string_release(str);
376 return tmp;
377 #endif
378 } else {
379 intval = zval_get_long(zvalue);
380 }
381
382 return psi_val_intval(tmp, real_type, intval);
383 }
384
385 /*
386 * set $ivar = to_float(dvar)
387 */
388 void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
389 {
390 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
391 token_t t = psi_decl_type_get_real(var->arg->type)->type;
392 impl_val *v = deref_impl_val(ret_val, var);
393
394 switch (t) {
395 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
396 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
397 #ifdef HAVE_LONG_DOUBLE
398 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
399 #endif
400 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
401 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
402 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
403 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
404 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
405 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
406 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
407 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
408 #if HAVE_INT128
409 case PSI_T_INT128: RETVAL_DOUBLE((double) v->i128); break;
410 case PSI_T_UINT128: RETVAL_DOUBLE((double) v->u128); break;
411 #endif
412 EMPTY_SWITCH_DEFAULT_CASE();
413 }
414 }
415
416 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
417 switch (real_type) {
418 case PSI_T_INT8: tmp->i8 = floatval; break;
419 case PSI_T_UINT8: tmp->u8 = floatval; break;
420 case PSI_T_INT16: tmp->i16 = floatval; break;
421 case PSI_T_UINT16: tmp->u16 = floatval; break;
422 case PSI_T_INT32: tmp->i32 = floatval; break;
423 case PSI_T_UINT32: tmp->u32 = floatval; break;
424 case PSI_T_INT64: tmp->i64 = floatval; break;
425 case PSI_T_UINT64: tmp->u64 = floatval; break;
426 #if HAVE_INT128
427 case PSI_T_INT128: tmp->i128 = floatval; break;
428 case PSI_T_UINT128: tmp->u128 = floatval; break;
429 #endif
430 case PSI_T_FLOAT: tmp->fval = floatval; break;
431 case PSI_T_DOUBLE: tmp->dval = floatval; break;
432 #ifdef HAVE_LONG_DOUBLE
433 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
434 #endif
435 EMPTY_SWITCH_DEFAULT_CASE();
436 }
437
438 return tmp;
439 }
440
441 /*
442 * let dvar = floatval($ivar)
443 */
444 impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
445 {
446 double floatval;
447 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE;
448
449 if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
450 floatval = ival->dval;
451 } else {
452 floatval = zval_get_double(zvalue);
453 }
454
455 return psi_val_floatval(tmp, real_type, floatval);
456 }
457
458 /*
459 * set $ivar = to_string(dvar)
460 */
461 void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
462 {
463 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
464 impl_val *ptr = deref_impl_val(ret_val, var);
465 char *str;
466
467 if (var->arg->var->array_size && var->arg->var->pointer_level == 1) {
468 str = (char *) ptr;
469 } else {
470 str = ptr->ptr;
471 }
472
473 if (str) {
474 RETVAL_STRING(str);
475 } else {
476 RETVAL_EMPTY_STRING();
477 }
478 }
479
480 /*
481 * set $ivar = to_string(dvar, num_exp)
482 */
483 void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
484 {
485 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
486 char *str = deref_impl_val(ret_val, var)->ptr;
487
488 if (str) {
489 struct psi_set_exp *sub_exp;
490
491 psi_plist_get(set->inner, 0, &sub_exp);
492 RETVAL_STRINGL(str, psi_num_exp_get_long(sub_exp->data.num, frame, NULL));
493 } else {
494 RETVAL_EMPTY_STRING();
495 }
496 }
497
498 /*
499 * let dvar = strval($ivar)
500 */
501 impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
502 {
503 if (ival && impl_type == PSI_T_STRING) {
504 if (ival->zend.str) {
505 tmp->ptr = ival->zend.str->val;
506 } else {
507 tmp->ptr = "";
508 }
509 } else {
510 zend_string *zs = zval_get_string(zvalue);
511 tmp->ptr = estrdup(zs->val);
512 *to_free = tmp->ptr;
513 zend_string_release(zs);
514 }
515
516 return tmp;
517 }
518
519 /*
520 * let dvar = pathval($ivar)
521 */
522 impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
523 {
524 tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
525 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
526 efree(tmp->ptr);
527 tmp->ptr = NULL;
528 return *to_free = NULL;
529 }
530 return tmp;
531 }
532
533 /*
534 * let dvar = strlen($ivar)
535 */
536 impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
537 {
538 if (ival && impl_type == PSI_T_STRING) {
539 if (ival->zend.str) {
540 tmp->u64 = ival->zend.str->len;
541 } else {
542 tmp->u64 = 0;
543 }
544 } else {
545 zend_string *zs = zval_get_string(zvalue);
546 tmp->u64 = zs->len;
547 zend_string_release(zs);
548 }
549
550 if (spec) {
551 psi_calc_cast(PSI_T_UINT64, tmp, psi_decl_type_get_real(spec->type)->type, tmp);
552 }
553 return tmp;
554 }
555
556 #if 0
557 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
558 {
559 memset(tmp, 0, sizeof(*tmp));
560 memcpy(tmp, ((char *) val) + size * i, size);
561 return tmp;
562 }
563 #endif
564
565 /*
566 * set $ivar = to_array(dvar,
567 * $foo = to_int(d_foo),
568 * $bar = to_string(d_bar),
569 * $baz = to_array(*d_next, ...)
570 */
571 void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
572 set->outer->data.func->handler(return_value, set, r_val, frame);
573 }
574
575 /*
576 * set $ivar = to_array(dvar, to_string(*dvar));
577 */
578 void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
579 {
580 struct psi_set_exp *sub_exp;
581 struct psi_decl_var *var;
582 impl_val *ret_val;
583 char *ptr;
584 size_t size;
585
586 array_init(return_value);
587
588 var = psi_set_exp_get_decl_var(set);
589 ret_val = deref_impl_val(r_val, var);
590 if ((intptr_t) ret_val <= (intptr_t) 0) {
591 return;
592 }
593
594 psi_plist_get(set->inner, 0, &sub_exp);
595
596 size = psi_decl_arg_get_size(var->arg);
597 for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
598 zval ele;
599
600 ZVAL_NULL(&ele);
601 sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
602 add_next_index_zval(return_value, &ele);
603 }
604 }
605
606 /*
607 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
608 */
609 void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
610 {
611 struct psi_set_exp *sub_exp;
612 struct psi_decl_var *var;
613 impl_val *ret_val;
614 char *ptr;
615 size_t size;
616 zend_long count;
617
618 array_init(return_value);
619
620 var = psi_set_exp_get_decl_var(set);
621 ret_val = deref_impl_val(r_val, var);
622 if ((intptr_t) ret_val <= (intptr_t) 0) {
623 return;
624 }
625
626 psi_plist_get(set->inner, 0, &sub_exp);
627 count = psi_num_exp_get_long(sub_exp->data.num, frame, NULL);
628 psi_plist_get(set->inner, 1, &sub_exp);
629
630 size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
631 for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
632 zval ele;
633
634 ZVAL_NULL(&ele);
635 sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
636 add_next_index_zval(return_value, &ele);
637 }
638 }
639
640 #include "call.h"
641
642 /*
643 * set $ivar = to_array(dvar,
644 * $foo = to_int(d_foo),
645 * $bar = to_string(d_bar));
646 */
647 void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
648 {
649 struct psi_set_exp *sub_exp;
650 struct psi_decl_var *var;
651 impl_val *ret_val;
652 size_t i = 0;
653
654 array_init(return_value);
655
656 var = psi_set_exp_get_decl_var(set);
657 ret_val = deref_impl_val(r_val, var);
658 if ((intptr_t) ret_val <= (intptr_t) 0) {
659 return;
660 }
661
662 while (psi_plist_get(set->inner, i++, &sub_exp)) {
663 zval ele;
664 struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
665 struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
666 struct psi_call_frame_symbol *sym;
667
668 sym = psi_call_frame_fetch_symbol(frame, dvar);
669 sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
670
671 ZVAL_NULL(&ele);
672 psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
673 add_assoc_zval_ex(return_value, ivar->name->val + 1, ivar->name->len - 1, &ele);
674 }
675 }
676
677 /*
678 * let dvar = count($ivar)
679 */
680 impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
681 {
682 return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue));
683 }
684
685 /*
686 * set $ivar = to_object(dvar)
687 */
688 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
689 {
690 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
691 impl_val *ret_val = deref_impl_val(r_val, var);
692
693 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
694 object_init_ex(return_value, psi_object_get_class_entry());
695 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
696 } else {
697 RETVAL_NULL();
698 }
699 }
700
701 /*
702 * let dvar = objval($ivar)
703 */
704 impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
705 {
706 psi_object *obj;
707
708 if (Z_TYPE_P(zvalue) != IS_OBJECT
709 || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) {
710 return NULL;
711 }
712
713 obj = PSI_OBJ(zvalue, NULL);
714 tmp->ptr = obj->data;
715
716 return tmp;
717 }
718