cpp: avoid errenous multiple expansions
[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_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 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_arg *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)->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:
252 RETVAL_DOUBLE((double) v->fval);
253 convert_to_long(return_value);
254 break;
255 case PSI_T_DOUBLE:
256 RETVAL_DOUBLE(v->dval);
257 convert_to_long(return_value);
258 break;
259 #ifdef HAVE_LONG_DOUBLE
260 case PSI_T_LONG_DOUBLE:
261 RETVAL_DOUBLE((double) v->ldval);
262 convert_to_long(return_value);
263 break;
264 #endif
265 EMPTY_SWITCH_DEFAULT_CASE();
266 }
267 }
268
269 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
270 switch (real_type) {
271 case PSI_T_INT8: tmp->i8 = intval; break;
272 case PSI_T_UINT8: tmp->u8 = intval; break;
273 case PSI_T_INT16: tmp->i16 = intval; break;
274 case PSI_T_UINT16: tmp->u16 = intval; break;
275 case PSI_T_INT32: tmp->i32 = intval; break;
276 case PSI_T_UINT32: tmp->u32 = intval; break;
277 case PSI_T_INT64: tmp->i64 = intval; break;
278 case PSI_T_UINT64: tmp->u64 = intval; break;
279 case PSI_T_INT: tmp->ival = intval; break;
280 case PSI_T_ENUM:
281 case PSI_T_LONG: tmp->lval = intval; break;
282 case PSI_T_FLOAT: tmp->fval = intval; break;
283 case PSI_T_DOUBLE: tmp->dval = intval; break;
284 #ifdef HAVE_LONG_DOUBLE
285 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
286 #endif
287 EMPTY_SWITCH_DEFAULT_CASE();
288 }
289
290 return tmp;
291 }
292
293 /*
294 * let dvar = intval($ivar)
295 */
296 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)
297 {
298 zend_long intval;
299 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_LONG;
300
301 if (ival && impl_type == PSI_T_INT) {
302 intval = ival->zend.lval;
303 } else {
304 intval = zval_get_long(zvalue);
305 }
306
307 return psi_val_intval(tmp, real_type, intval);
308 }
309
310 /*
311 * set $ivar = to_float(dvar)
312 */
313 void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
314 {
315 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
316 token_t t = psi_decl_type_get_real(var->arg->type)->type;
317 impl_val *v = deref_impl_val(ret_val, var);
318
319 switch (t) {
320 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
321 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
322 #ifdef HAVE_LONG_DOUBLE
323 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
324 #endif
325 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
326 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
327 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
328 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
329 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
330 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
331 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
332 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
333 EMPTY_SWITCH_DEFAULT_CASE();
334 }
335 }
336
337 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
338 switch (real_type) {
339 case PSI_T_INT8: tmp->i8 = floatval; break;
340 case PSI_T_UINT8: tmp->u8 = floatval; break;
341 case PSI_T_INT16: tmp->i16 = floatval; break;
342 case PSI_T_UINT16: tmp->u16 = floatval; break;
343 case PSI_T_INT32: tmp->i32 = floatval; break;
344 case PSI_T_UINT32: tmp->u32 = floatval; break;
345 case PSI_T_INT64: tmp->i64 = floatval; break;
346 case PSI_T_UINT64: tmp->u64 = floatval; break;
347 case PSI_T_FLOAT: tmp->fval = floatval; break;
348 case PSI_T_DOUBLE: tmp->dval = floatval; break;
349 #ifdef HAVE_LONG_DOUBLE
350 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
351 #endif
352 EMPTY_SWITCH_DEFAULT_CASE();
353 }
354
355 return tmp;
356 }
357
358 /*
359 * let dvar = floatval($ivar)
360 */
361 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)
362 {
363 double floatval;
364 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE;
365
366 if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
367 floatval = ival->dval;
368 } else {
369 floatval = zval_get_double(zvalue);
370 }
371
372 return psi_val_floatval(tmp, real_type, floatval);
373 }
374
375 /*
376 * set $ivar = to_string(dvar)
377 */
378 void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
379 {
380 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
381 impl_val *ptr = deref_impl_val(ret_val, var);
382 char *str;
383
384 if (var->arg->var->array_size) {
385 str = (char *) ptr;
386 } else {
387 str = ptr->ptr;
388 }
389
390 if (str) {
391 RETVAL_STRING(str);
392 } else {
393 RETVAL_EMPTY_STRING();
394 }
395 }
396
397 /*
398 * set $ivar = to_string(dvar, num_exp)
399 */
400 void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
401 {
402 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
403 char *str = deref_impl_val(ret_val, var)->ptr;
404
405 if (str) {
406 struct psi_set_exp *sub_exp;
407
408 psi_plist_get(set->inner, 0, &sub_exp);
409 RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame, NULL));
410 } else {
411 RETVAL_EMPTY_STRING();
412 }
413 }
414
415 /*
416 * let dvar = strval($ivar)
417 */
418 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)
419 {
420 if (ival && impl_type == PSI_T_STRING) {
421 if (ival->zend.str) {
422 tmp->ptr = ival->zend.str->val;
423 } else {
424 tmp->ptr = "";
425 }
426 } else {
427 zend_string *zs = zval_get_string(zvalue);
428 tmp->ptr = estrdup(zs->val);
429 *to_free = tmp->ptr;
430 zend_string_release(zs);
431 }
432
433 return tmp;
434 }
435
436 /*
437 * let dvar = pathval($ivar)
438 */
439 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)
440 {
441 tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
442 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
443 efree(tmp->ptr);
444 tmp->ptr = NULL;
445 return *to_free = NULL;
446 }
447 return tmp;
448 }
449
450 /*
451 * let dvar = strlen($ivar)
452 */
453 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)
454 {
455 if (ival && impl_type == PSI_T_STRING) {
456 if (ival->zend.str) {
457 tmp->lval = ival->zend.str->len;
458 } else {
459 tmp->lval = 0;
460 }
461 } else {
462 zend_string *zs = zval_get_string(zvalue);
463 tmp->lval = zs->len;
464 zend_string_release(zs);
465 }
466
467 return tmp;
468 }
469
470 #if 0
471 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
472 {
473 memset(tmp, 0, sizeof(*tmp));
474 memcpy(tmp, ((char *) val) + size * i, size);
475 return tmp;
476 }
477 #endif
478
479 /*
480 * set $ivar = to_array(dvar,
481 * $foo = to_int(d_foo),
482 * $bar = to_string(d_bar),
483 * $baz = to_array(*d_next, ...)
484 */
485 void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
486 set->outer->data.func->handler(return_value, set, r_val, frame);
487 }
488
489 /*
490 * set $ivar = to_array(dvar, to_string(*dvar));
491 */
492 void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
493 {
494 struct psi_set_exp *sub_exp;
495 struct psi_decl_var *var;
496 impl_val *ret_val;
497 char *ptr;
498 size_t size;
499
500 array_init(return_value);
501
502 var = psi_set_exp_get_decl_var(set);
503 ret_val = deref_impl_val(r_val, var);
504 if ((intptr_t) ret_val <= (intptr_t) 0) {
505 return;
506 }
507
508 psi_plist_get(set->inner, 0, &sub_exp);
509
510 size = psi_decl_arg_get_size(var->arg);
511 for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
512 zval ele;
513
514 ZVAL_NULL(&ele);
515 sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
516 add_next_index_zval(return_value, &ele);
517 }
518 }
519
520 /*
521 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
522 */
523 void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
524 {
525 struct psi_set_exp *sub_exp;
526 struct psi_decl_var *var;
527 impl_val *ret_val;
528 char *ptr;
529 size_t size;
530 zend_long count;
531
532 array_init(return_value);
533
534 var = psi_set_exp_get_decl_var(set);
535 ret_val = deref_impl_val(r_val, var);
536 if ((intptr_t) ret_val <= (intptr_t) 0) {
537 return;
538 }
539
540 psi_plist_get(set->inner, 0, &sub_exp);
541 count = psi_long_num_exp(sub_exp->data.num, frame, NULL);
542 psi_plist_get(set->inner, 1, &sub_exp);
543
544 for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
545 size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
546 zval ele;
547
548 ZVAL_NULL(&ele);
549 sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
550 add_next_index_zval(return_value, &ele);
551 }
552 }
553
554 #include "call.h"
555
556 /*
557 * set $ivar = to_array(dvar,
558 * $foo = to_int(d_foo),
559 * $bar = to_string(d_bar));
560 */
561 void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
562 {
563 struct psi_set_exp *sub_exp;
564 struct psi_decl_var *var;
565 impl_val *ret_val;
566 size_t i = 0;
567
568 array_init(return_value);
569
570 var = psi_set_exp_get_decl_var(set);
571 ret_val = deref_impl_val(r_val, var);
572 if ((intptr_t) ret_val <= (intptr_t) 0) {
573 return;
574 }
575
576 while (psi_plist_get(set->inner, i++, &sub_exp)) {
577 zval ele;
578 struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
579 struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
580 struct psi_call_frame_symbol *sym;
581
582 sym = psi_call_frame_fetch_symbol(frame, dvar);
583 sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
584
585 ZVAL_NULL(&ele);
586 psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
587 add_assoc_zval(return_value, ivar->name + 1, &ele);
588 }
589 }
590
591 /*
592 * let dvar = count($ivar)
593 */
594 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)
595 {
596 return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue));
597 }
598
599 /*
600 * set $ivar = to_object(dvar)
601 */
602 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
603 {
604 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
605 impl_val *ret_val = deref_impl_val(r_val, var);
606
607 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
608 object_init_ex(return_value, psi_object_get_class_entry());
609 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
610 } else {
611 RETVAL_NULL();
612 }
613 }
614
615 /*
616 * let dvar = objval($ivar)
617 */
618 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)
619 {
620 psi_object *obj;
621
622 if (Z_TYPE_P(zvalue) != IS_OBJECT
623 || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) {
624 return NULL;
625 }
626
627 obj = PSI_OBJ(zvalue, NULL);
628 tmp->ptr = obj->data;
629
630 return tmp;
631 }
632