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 #include <Zend/zend_smart_str.h>
35 struct psi_let_exp
*psi_let_exp_init_ex(struct psi_decl_var
*var
,
36 enum psi_let_exp_kind kind
, void *data
)
38 struct psi_let_exp
*val
= psi_let_exp_init(kind
, data
);
43 struct psi_let_exp
*psi_let_exp_init(enum psi_let_exp_kind kind
, void *data
)
45 struct psi_let_exp
*let
= calloc(1, sizeof(*let
));
46 switch (let
->kind
= kind
) {
54 let
->data
.alloc
= data
;
56 case PSI_LET_CALLBACK
:
57 let
->data
.callback
= data
;
60 let
->data
.func
= data
;
71 void psi_let_exp_free(struct psi_let_exp
**let_ptr
)
74 struct psi_let_exp
*let
= *let_ptr
;
81 psi_num_exp_free(&let
->data
.num
);
84 psi_let_calloc_free(&let
->data
.alloc
);
86 case PSI_LET_CALLBACK
:
87 psi_let_callback_free(&let
->data
.callback
);
90 psi_let_func_free(&let
->data
.func
);
93 psi_decl_var_free(&let
->data
.var
);
99 psi_decl_var_free(&let
->var
);
105 void psi_let_exp_dump(int fd
, struct psi_let_exp
*val
, unsigned level
, int last
)
108 /* only if not directly after `set ...` */
109 dprintf(fd
, "%s", psi_t_indent(level
));
113 if (val
->var
->token
) {
114 psi_decl_var_dump(fd
, val
->var
);
118 if (val
->is_reference
) {
127 psi_decl_var_dump(fd
, val
->data
.var
);
128 dprintf(fd
, "\t/* fqn=%s */", val
->data
.var
->fqn
->val
);
131 psi_let_calloc_dump(fd
, val
->data
.alloc
);
133 case PSI_LET_CALLBACK
:
134 psi_let_callback_dump(fd
, val
->data
.callback
, level
);
137 psi_let_func_dump(fd
, val
->data
.func
, level
);
140 psi_num_exp_dump(fd
, val
->data
.num
);
148 dprintf(fd
, "\t/* fqn=%s */", val
->var
->fqn
->val
);
160 bool psi_let_exp_validate(struct psi_data
*data
, struct psi_let_exp
*val
,
161 struct psi_validate_scope
*scope
)
163 struct psi_decl_var
*dvar
= psi_let_exp_get_decl_var(val
);
167 if (!psi_decl_var_validate(data
, val
->data
.var
, scope
)) {
168 data
->error(data
, dvar
->token
? : **(struct psi_token
***) &val
->data
,
169 PSI_WARNING
, "Unknown variable '%s' in temp let statment of implementation '%s'",
170 dvar
->name
->val
, scope
->impl
->func
->name
->val
);
176 if (!psi_decl_var_validate(data
, dvar
, scope
)) {
177 data
->error(data
, dvar
->token
? : **(struct psi_token
***) &val
->data
,
178 PSI_WARNING
, "Unknown variable '%s' in let statement of implementation '%s'",
179 dvar
->name
->val
, scope
->impl
->func
->name
->val
);
188 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
189 /* e.g. let foo = *bar; */
190 val
->var
->pointer_level
= val
->data
.var
->pointer_level
;
191 val
->var
->arg
= val
->data
.var
->arg
;
194 if (!psi_num_exp_validate(data
, val
->data
.num
, scope
)) {
199 if (!psi_num_exp_validate(data
, val
->data
.alloc
->nmemb
, scope
)) {
202 if (!psi_num_exp_validate(data
, val
->data
.alloc
->size
, scope
)) {
206 case PSI_LET_CALLBACK
:
207 if (!psi_let_func_validate(data
, val
->data
.callback
->func
, scope
)) {
210 if (!psi_let_callback_validate(data
, val
->data
.callback
, scope
)) {
215 if (!psi_let_func_validate(data
, val
->data
.func
, scope
)) {
224 void *psi_let_exp_exec(struct psi_let_exp
*val
, struct psi_decl_arg
*darg
,
225 void *actual_location
, size_t actual_size
, struct psi_call_frame
*frame
)
227 struct psi_call_frame_symbol
*frame_sym
;
229 frame_sym
= psi_call_frame_fetch_symbol(frame
, val
->var
);
233 /* FIXME: sizeof_decl_arg */
234 if (darg
&& darg
->var
->array_size
) {
235 frame_sym
->temp_val
.ptr
= ecalloc(1, psi_decl_arg_get_size(darg
));
237 memset(&frame_sym
->temp_val
, 0, sizeof(frame_sym
->temp_val
));
243 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
244 struct psi_let_stmt
*let_temp
= psi_impl_get_let(impl
, val
->data
.var
);
245 struct psi_call_frame_symbol
*temp_arg
;
247 temp_arg
= psi_call_frame_fetch_symbol(frame
, let_temp
->exp
->var
);
248 frame_sym
->temp_val
= *deref_impl_val(temp_arg
->ptr
, val
->data
.var
);
254 zend_long n
= psi_num_exp_get_long(val
->data
.alloc
->nmemb
, frame
, NULL
);
255 zend_long s
= psi_num_exp_get_long(val
->data
.alloc
->size
, frame
, NULL
);
258 if (val
->data
.alloc
->static_memory
) {
259 tmp
= safe_pemalloc(n
, s
, sizeof(void *), 1);
261 tmp
= *psi_call_frame_push_auto(frame
, safe_emalloc(n
, s
, sizeof(void *)));
264 memset(tmp
, 0, n
* s
+ sizeof(void *));
265 frame_sym
->temp_val
.ptr
= tmp
;
272 token_t val_type
= psi_decl_type_get_real(val
->var
->arg
->type
)->type
;
273 token_t res_type
= psi_num_exp_exec(val
->data
.num
, &res
, frame
, NULL
);
275 if (val_type
== res_type
) {
276 frame_sym
->temp_val
= res
;
278 psi_calc_cast(res_type
, &res
, val_type
, &frame_sym
->temp_val
);
283 case PSI_LET_CALLBACK
:
284 frame_sym
->temp_val
.ptr
= val
->data
.callback
->decl
->sym
;
288 if (!psi_let_func_exec(val
, val
->data
.func
, darg
, frame
)) {
294 if (val
->is_reference
) {
295 frame_sym
->ptr
= &frame_sym
->ival_ptr
;
297 frame_sym
->ptr
= frame_sym
->ival_ptr
;
300 if (actual_location
) {
301 assert(!val
->is_reference
|| actual_size
== SIZEOF_VOID_P
);
302 memcpy(actual_location
, frame_sym
->ptr
, actual_size
);
303 frame_sym
->ptr
= actual_location
;
306 return frame_sym
->ptr
;
309 struct psi_let_func
* psi_let_exp_get_func(struct psi_let_exp
* exp
)
313 case PSI_LET_CALLBACK
:
314 return exp
->data
.callback
->func
;
316 return exp
->data
.func
;
324 struct psi_decl_var
*psi_let_exp_get_decl_var(struct psi_let_exp
*val
)
327 zend_string
*name
= psi_let_exp_get_decl_var_name(val
);
330 val
->var
= psi_decl_var_init(name
, 0, 0);
331 zend_string_release(name
);
337 struct psi_impl_var
*psi_let_exp_get_impl_var(struct psi_let_exp
*val
)
339 struct psi_let_func
* fn
= psi_let_exp_get_func(val
);
340 return fn
? fn
->var
: NULL
;
343 zend_string
*psi_let_exp_get_decl_var_name(struct psi_let_exp
* val
)
345 struct psi_impl_var
* var
;
348 return zend_string_copy(val
->var
->name
);
351 var
= psi_let_exp_get_impl_var(val
);
353 smart_str name
= {0};
355 smart_str_appendl_ex(&name
, &var
->name
->val
[1], var
->name
->len
- 1, 1);
357 return smart_str_extract(&name
);