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