parser: RETURN [<native call> AS] SET_FUNC
[m6w6/ext-psi] / src / types / let_exp.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 "call.h"
29 #include "calc.h"
30
31 #include <assert.h>
32
33 struct psi_let_exp *psi_let_exp_init_ex(struct psi_decl_var *var,
34 enum psi_let_exp_kind kind, void *data)
35 {
36 struct psi_let_exp *val = psi_let_exp_init(kind, data);
37 val->var = var;
38 return val;
39 }
40
41 struct psi_let_exp *psi_let_exp_init(enum psi_let_exp_kind kind, void *data)
42 {
43 struct psi_let_exp *let = calloc(1, sizeof(*let));
44 switch (let->kind = kind) {
45 case PSI_LET_NULL:
46 assert(!data);
47 break;
48 case PSI_LET_NUMEXP:
49 let->data.num = data;
50 break;
51 case PSI_LET_CALLOC:
52 let->data.alloc = data;
53 break;
54 case PSI_LET_CALLBACK:
55 let->data.callback = data;
56 break;
57 case PSI_LET_FUNC:
58 let->data.func = data;
59 break;
60 case PSI_LET_TMP:
61 let->data.var = data;
62 break;
63 default:
64 assert(0);
65 }
66 return let;
67 }
68
69 void psi_let_exp_free(struct psi_let_exp **let_ptr)
70 {
71 if (*let_ptr) {
72 struct psi_let_exp *let = *let_ptr;
73
74 *let_ptr = NULL;
75 switch (let->kind) {
76 case PSI_LET_NULL:
77 break;
78 case PSI_LET_NUMEXP:
79 psi_num_exp_free(&let->data.num);
80 break;
81 case PSI_LET_CALLOC:
82 psi_let_calloc_free(&let->data.alloc);
83 break;
84 case PSI_LET_CALLBACK:
85 psi_let_callback_free(&let->data.callback);
86 break;
87 case PSI_LET_FUNC:
88 psi_let_func_free(&let->data.func);
89 break;
90 case PSI_LET_TMP:
91 psi_decl_var_free(&let->data.var);
92 break;
93 default:
94 assert(0);
95 }
96 if (let->var) {
97 psi_decl_var_free(&let->var);
98 }
99 free(let);
100 }
101 }
102
103 void psi_let_exp_dump(int fd, struct psi_let_exp *val, unsigned level, int last)
104 {
105 if (level > 1) {
106 /* only if not directly after `set ...` */
107 dprintf(fd, "%s", psi_t_indent(level));
108 }
109
110 if (val->var) {
111 if (val->var->token) {
112 psi_decl_var_dump(fd, val->var);
113 dprintf(fd, " = ");
114 }
115 }
116 if (val->is_reference) {
117 dprintf(fd, "&");
118 }
119
120 switch (val->kind) {
121 case PSI_LET_NULL:
122 dprintf(fd, "NULL");
123 break;
124 case PSI_LET_TMP:
125 psi_decl_var_dump(fd, val->data.var);
126 dprintf(fd, "\t/* fqn=%s */", val->data.var->fqn);
127 break;
128 case PSI_LET_CALLOC:
129 psi_let_calloc_dump(fd, val->data.alloc);
130 break;
131 case PSI_LET_CALLBACK:
132 psi_let_callback_dump(fd, val->data.callback, level);
133 break;
134 case PSI_LET_FUNC:
135 psi_let_func_dump(fd, val->data.func, level);
136 break;
137 case PSI_LET_NUMEXP:
138 psi_num_exp_dump(fd, val->data.num);
139 break;
140
141 default:
142 assert(0);
143 }
144
145 if (val->var) {
146 dprintf(fd, "\t/* fqn=%s */", val->var->fqn);
147 }
148
149 if (level > 1) {
150 if (!last) {
151 dprintf(fd, ",");
152 }
153 } else {
154 dprintf(fd, ";");
155 }
156 }
157
158 bool psi_let_exp_validate(struct psi_data *data, struct psi_let_exp *val,
159 struct psi_impl *impl)
160 {
161 struct psi_decl_var *dvar = psi_let_exp_get_decl_var(val);
162
163 switch (val->kind) {
164 case PSI_LET_TMP:
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);
169 return false;
170 }
171 break;
172
173 default:
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);
178 return false;
179 }
180 break;
181 }
182 switch (val->kind) {
183 case PSI_LET_NULL:
184 break;
185 case PSI_LET_TMP:
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;
190 break;
191 case PSI_LET_NUMEXP:
192 if (!psi_num_exp_validate(data, val->data.num, impl, NULL, val, NULL, NULL)) {
193 return false;
194 }
195 break;
196 case PSI_LET_CALLOC:
197 if (!psi_num_exp_validate(data, val->data.alloc->nmemb, impl, NULL, val, NULL, NULL)) {
198 return false;
199 }
200 if (!psi_num_exp_validate(data, val->data.alloc->size, impl, NULL, val, NULL, NULL)) {
201 return false;
202 }
203 break;
204 case PSI_LET_CALLBACK:
205 if (!psi_let_func_validate(data, val, val->data.callback->func, impl)) {
206 return false;
207 }
208 if (!psi_let_callback_validate(data, val, val->data.callback, impl)) {
209 return false;
210 }
211 break;
212 case PSI_LET_FUNC:
213 if (!psi_let_func_validate(data, val, val->data.func, impl)) {
214 return false;
215 }
216 break;
217 }
218
219 return true;
220 }
221
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)
224 {
225 struct psi_call_frame_symbol *frame_sym;
226
227 frame_sym = psi_call_frame_fetch_symbol(frame, val->var);
228
229 switch (val->kind) {
230 case PSI_LET_NULL:
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));
234 } else {
235 memset(&frame_sym->temp_val, 0, sizeof(frame_sym->temp_val));
236 }
237 break;
238
239 case PSI_LET_TMP:
240 {
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;
244
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);
247 }
248 break;
249
250 case PSI_LET_CALLOC:
251 {
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);
254 void *tmp;
255
256 if (val->data.alloc->static_memory) {
257 tmp = safe_pemalloc(n, s, sizeof(void *), 1);
258 } else {
259 tmp = *psi_call_frame_push_auto(frame, safe_emalloc(n, s, sizeof(void *)));
260 }
261
262 memset(tmp, 0, n * s + sizeof(void *));
263 frame_sym->temp_val.ptr = tmp;
264 }
265 break;
266
267 case PSI_LET_NUMEXP:
268 {
269 impl_val res;
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);
272
273 if (val_type == res_type) {
274 frame_sym->temp_val = res;
275 } else {
276 psi_calc_cast(res_type, &res, val_type, &frame_sym->temp_val);
277 }
278 }
279 break;
280
281 case PSI_LET_CALLBACK:
282 frame_sym->temp_val.ptr = val->data.callback->decl->sym;
283 break;
284
285 case PSI_LET_FUNC:
286 if (!psi_let_func_exec(val, val->data.func, darg, frame)) {
287 return NULL;
288 }
289 break;
290 }
291
292 if (val->is_reference) {
293 frame_sym->ptr = &frame_sym->ival_ptr;
294 } else {
295 frame_sym->ptr = frame_sym->ival_ptr;
296 }
297
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;
302 }
303
304 return frame_sym->ptr;
305 }
306
307 struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp)
308 {
309 if (exp) {
310 switch (exp->kind) {
311 case PSI_LET_CALLBACK:
312 return exp->data.callback->func;
313 case PSI_LET_FUNC:
314 return exp->data.func;
315 default:
316 break;
317 }
318 }
319 return NULL;
320 }
321
322 struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val)
323 {
324 if (!val->var) {
325 const char *name = psi_let_exp_get_decl_var_name(val);
326
327 if (name) {
328 val->var = psi_decl_var_init(name, 0, 0);
329 }
330 }
331 return val->var;
332 }
333
334 struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val)
335 {
336 struct psi_let_func* fn = psi_let_exp_get_func(val);
337 return fn ? fn->var : NULL;
338 }
339
340 const char* psi_let_exp_get_decl_var_name(struct psi_let_exp* val)
341 {
342 struct psi_impl_var* var;
343 if (val->var) {
344 return val->var->name;
345 }
346 var = psi_let_exp_get_impl_var(val);
347 if (var) {
348 return &var->name[1];
349 }
350 return NULL;
351 }