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