1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
33 struct psi_let_exp
*psi_let_exp_init_ex(struct psi_decl_var
*var
,
34 enum psi_let_exp_kind kind
, void *data
)
36 struct psi_let_exp
*val
= psi_let_exp_init(kind
, data
);
41 struct psi_let_exp
*psi_let_exp_init(enum psi_let_exp_kind kind
, void *data
)
43 struct psi_let_exp
*let
= calloc(1, sizeof(*let
));
44 switch (let
->kind
= kind
) {
52 let
->data
.alloc
= data
;
54 case PSI_LET_CALLBACK
:
55 let
->data
.callback
= data
;
58 let
->data
.func
= data
;
69 void psi_let_exp_free(struct psi_let_exp
**let_ptr
)
72 struct psi_let_exp
*let
= *let_ptr
;
79 psi_num_exp_free(&let
->data
.num
);
82 psi_let_calloc_free(&let
->data
.alloc
);
84 case PSI_LET_CALLBACK
:
85 psi_let_callback_free(&let
->data
.callback
);
88 psi_let_func_free(&let
->data
.func
);
91 psi_decl_var_free(&let
->data
.var
);
97 psi_decl_var_free(&let
->var
);
103 void psi_let_exp_dump(int fd
, struct psi_let_exp
*val
, unsigned level
, int last
)
106 /* only if not directly after `set ...` */
107 dprintf(fd
, "%s", psi_t_indent(level
));
111 if (val
->var
->token
) {
112 psi_decl_var_dump(fd
, val
->var
);
116 if (val
->is_reference
) {
125 psi_decl_var_dump(fd
, val
->data
.var
);
126 dprintf(fd
, "\t/* fqn=%s */", val
->data
.var
->fqn
);
129 psi_let_calloc_dump(fd
, val
->data
.alloc
);
131 case PSI_LET_CALLBACK
:
132 psi_let_callback_dump(fd
, val
->data
.callback
, level
);
135 psi_let_func_dump(fd
, val
->data
.func
, level
);
138 psi_num_exp_dump(fd
, val
->data
.num
);
146 dprintf(fd
, "\t/* fqn=%s */", val
->var
->fqn
);
158 bool psi_let_exp_validate(struct psi_data
*data
, struct psi_let_exp
*val
,
159 struct psi_impl
*impl
)
161 struct psi_decl_var
*dvar
= psi_let_exp_get_decl_var(val
);
165 if (!psi_decl_var_validate(data
, val
->data
.var
, impl
, impl
->decl
, val
, NULL
)) {
166 data
->error(data
, dvar
->token
? : **(struct psi_token
***) &val
->data
,
167 PSI_WARNING
, "Unknown variable '%s' in temp let statment of implementation '%s'",
168 dvar
->name
, impl
->func
->name
);
174 if (!psi_decl_var_validate(data
, dvar
, impl
, impl
->decl
, val
, NULL
)) {
175 data
->error(data
, dvar
->token
? : **(struct psi_token
***) &val
->data
,
176 PSI_WARNING
, "Unknown variable '%s' in let statement of implementation '%s'",
177 dvar
->name
, impl
->func
->name
);
186 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
187 /* e.g. let foo = *bar; */
188 val
->var
->pointer_level
= val
->data
.var
->pointer_level
;
189 val
->var
->arg
= val
->data
.var
->arg
;
192 if (!psi_num_exp_validate(data
, val
->data
.num
, impl
, NULL
, val
, NULL
, NULL
)) {
197 if (!psi_num_exp_validate(data
, val
->data
.alloc
->nmemb
, impl
, NULL
, val
, NULL
, NULL
)) {
200 if (!psi_num_exp_validate(data
, val
->data
.alloc
->size
, impl
, NULL
, val
, NULL
, NULL
)) {
204 case PSI_LET_CALLBACK
:
205 if (!psi_let_func_validate(data
, val
, val
->data
.callback
->func
, impl
)) {
208 if (!psi_let_callback_validate(data
, val
, val
->data
.callback
, impl
)) {
213 if (!psi_let_func_validate(data
, val
, val
->data
.func
, impl
)) {
222 void *psi_let_exp_exec(struct psi_let_exp
*val
, struct psi_decl_arg
*darg
,
223 void *actual_location
, size_t actual_size
, struct psi_call_frame
*frame
)
225 struct psi_call_frame_symbol
*frame_sym
;
227 frame_sym
= psi_call_frame_fetch_symbol(frame
, val
->var
);
231 /* FIXME: sizeof_decl_arg */
232 if (darg
&& darg
->var
->array_size
) {
233 frame_sym
->temp_val
.ptr
= ecalloc(1, psi_decl_arg_get_size(darg
));
235 memset(&frame_sym
->temp_val
, 0, sizeof(frame_sym
->temp_val
));
241 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
242 struct psi_let_stmt
*let_temp
= psi_impl_get_let(impl
, val
->data
.var
);
243 struct psi_call_frame_symbol
*temp_arg
;
245 temp_arg
= psi_call_frame_fetch_symbol(frame
, let_temp
->exp
->var
);
246 frame_sym
->temp_val
= *deref_impl_val(temp_arg
->ptr
, val
->data
.var
);
252 zend_long n
= psi_long_num_exp(val
->data
.alloc
->nmemb
, frame
, NULL
);
253 zend_long s
= psi_long_num_exp(val
->data
.alloc
->size
, frame
, NULL
);
256 if (val
->data
.alloc
->static_memory
) {
257 tmp
= safe_pemalloc(n
, s
, sizeof(void *), 1);
259 tmp
= *psi_call_frame_push_auto(frame
, safe_emalloc(n
, s
, sizeof(void *)));
262 memset(tmp
, 0, n
* s
+ sizeof(void *));
263 frame_sym
->temp_val
.ptr
= tmp
;
270 token_t val_type
= psi_decl_type_get_real(val
->var
->arg
->type
)->type
;
271 token_t res_type
= psi_num_exp_exec(val
->data
.num
, &res
, frame
, NULL
);
273 if (val_type
== res_type
) {
274 frame_sym
->temp_val
= res
;
276 psi_calc_cast(res_type
, &res
, val_type
, &frame_sym
->temp_val
);
281 case PSI_LET_CALLBACK
:
282 frame_sym
->temp_val
.ptr
= val
->data
.callback
->decl
->sym
;
286 if (!psi_let_func_exec(val
, val
->data
.func
, darg
, frame
)) {
292 if (val
->is_reference
) {
293 frame_sym
->ptr
= &frame_sym
->ival_ptr
;
295 frame_sym
->ptr
= frame_sym
->ival_ptr
;
298 if (actual_location
) {
299 assert(!val
->is_reference
|| actual_size
== SIZEOF_VOID_P
);
300 memcpy(actual_location
, frame_sym
->ptr
, actual_size
);
301 frame_sym
->ptr
= actual_location
;
304 return frame_sym
->ptr
;
307 struct psi_let_func
* psi_let_exp_get_func(struct psi_let_exp
* exp
)
311 case PSI_LET_CALLBACK
:
312 return exp
->data
.callback
->func
;
314 return exp
->data
.func
;
322 struct psi_decl_var
*psi_let_exp_get_decl_var(struct psi_let_exp
*val
)
325 const char *name
= psi_let_exp_get_decl_var_name(val
);
328 val
->var
= psi_decl_var_init(name
, 0, 0);
334 struct psi_impl_var
*psi_let_exp_get_impl_var(struct psi_let_exp
*val
)
336 struct psi_let_func
* fn
= psi_let_exp_get_func(val
);
337 return fn
? fn
->var
: NULL
;
340 const char* psi_let_exp_get_decl_var_name(struct psi_let_exp
* val
)
342 struct psi_impl_var
* var
;
344 return val
->var
->name
;
346 var
= psi_let_exp_get_impl_var(val
);
348 return &var
->name
[1];