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