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