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