raising the head after a three-weeks refactoring
[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
30 #include <assert.h>
31
32 struct psi_let_exp *psi_let_exp_init_ex(struct psi_decl_var *var,
33 enum psi_let_exp_kind kind, void *data)
34 {
35 struct psi_let_exp *val = psi_let_exp_init(kind, data);
36 val->var = var;
37 return val;
38 }
39
40 struct psi_let_exp *psi_let_exp_init(enum psi_let_exp_kind kind, void *data)
41 {
42 struct psi_let_exp *let = calloc(1, sizeof(*let));
43 switch (let->kind = kind) {
44 case PSI_LET_NULL:
45 assert(!data);
46 break;
47 case PSI_LET_NUMEXP:
48 let->data.num = data;
49 break;
50 case PSI_LET_CALLOC:
51 let->data.alloc = data;
52 break;
53 case PSI_LET_CALLBACK:
54 let->data.callback = data;
55 break;
56 case PSI_LET_FUNC:
57 let->data.func = data;
58 break;
59 case PSI_LET_TMP:
60 let->data.var = data;
61 break;
62 default:
63 assert(0);
64 }
65 return let;
66 }
67
68 void psi_let_exp_free(struct psi_let_exp **let_ptr)
69 {
70 if (*let_ptr) {
71 struct psi_let_exp *let = *let_ptr;
72
73 *let_ptr = NULL;
74 switch (let->kind) {
75 case PSI_LET_NULL:
76 break;
77 case PSI_LET_NUMEXP:
78 psi_num_exp_free(&let->data.num);
79 break;
80 case PSI_LET_CALLOC:
81 psi_let_calloc_free(&let->data.alloc);
82 break;
83 case PSI_LET_CALLBACK:
84 psi_let_callback_free(&let->data.callback);
85 break;
86 case PSI_LET_FUNC:
87 psi_let_func_free(&let->data.func);
88 break;
89 case PSI_LET_TMP:
90 psi_decl_var_free(&let->data.var);
91 break;
92 default:
93 assert(0);
94 }
95 if (let->var) {
96 psi_decl_var_free(&let->var);
97 }
98 free(let);
99 }
100 }
101
102 void psi_let_exp_dump(int fd, struct psi_let_exp *val, unsigned level, int last)
103 {
104 if (level > 1) {
105 /* only if not directly after `set ...` */
106 dprintf(fd, "%s", psi_t_indent(level));
107 }
108
109 if (val->var) {
110 if (val->var->token) {
111 psi_decl_var_dump(fd, val->var);
112 dprintf(fd, " = ");
113 }
114 }
115 if (val->is_reference) {
116 dprintf(fd, "&");
117 }
118
119 switch (val->kind) {
120 case PSI_LET_NULL:
121 dprintf(fd, "NULL");
122 break;
123 case PSI_LET_TMP:
124 psi_decl_var_dump(fd, val->data.var);
125 dprintf(fd, "\t/* fqn=%s */", val->data.var->fqn);
126 break;
127 case PSI_LET_CALLOC:
128 psi_let_calloc_dump(fd, val->data.alloc);
129 break;
130 case PSI_LET_CALLBACK:
131 psi_let_callback_dump(fd, val->data.callback, level);
132 break;
133 case PSI_LET_FUNC:
134 psi_let_func_dump(fd, val->data.func, level);
135 break;
136 case PSI_LET_NUMEXP:
137 psi_num_exp_dump(fd, val->data.num);
138 break;
139
140 default:
141 assert(0);
142 }
143
144 if (val->var) {
145 dprintf(fd, "\t/* fqn=%s */", val->var->fqn);
146 }
147
148 if (level > 1) {
149 if (!last) {
150 dprintf(fd, ",");
151 }
152 } else {
153 dprintf(fd, ";");
154 }
155 }
156
157 bool psi_let_exp_validate(struct psi_data *data, struct psi_let_exp *val,
158 struct psi_impl *impl)
159 {
160 struct psi_decl_var *dvar = psi_let_exp_get_decl_var(val);
161
162 switch (val->kind) {
163 case PSI_LET_TMP:
164 if (!psi_decl_var_validate(data, val->data.var, impl->decl, val, NULL)) {
165 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
166 PSI_WARNING, "Unknown variable '%s'", dvar->name);
167 return false;
168 }
169 break;
170
171 default:
172 if (!psi_decl_var_validate(data, dvar, impl->decl, val, NULL)) {
173 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
174 PSI_WARNING, "Unknown variable '%s'", dvar->name);
175 return false;
176 }
177 break;
178 }
179
180 switch (val->kind) {
181 case PSI_LET_NULL:
182 break;
183 case PSI_LET_TMP:
184 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
185 /* e.g. let foo = *bar; */
186 val->var->pointer_level = val->data.var->pointer_level;
187 val->var->arg = val->data.var->arg;
188 break;
189 case PSI_LET_NUMEXP:
190 if (!psi_num_exp_validate(data, val->data.num, impl, NULL, val, NULL, NULL)) {
191 return false;
192 }
193 break;
194 case PSI_LET_CALLOC:
195 if (!psi_num_exp_validate(data, val->data.alloc->nmemb, impl, NULL, val, NULL, NULL)) {
196 return false;
197 }
198 if (!psi_num_exp_validate(data, val->data.alloc->size, impl, NULL, val, NULL, NULL)) {
199 return false;
200 }
201 break;
202 case PSI_LET_CALLBACK:
203 if (!psi_let_func_validate(data, val, val->data.callback->func, impl)) {
204 return false;
205 }
206 if (!psi_let_callback_validate(data, val, val->data.callback, impl)) {
207 return false;
208 }
209 break;
210 case PSI_LET_FUNC:
211 if (!psi_let_func_validate(data, val, val->data.func, impl)) {
212 return false;
213 }
214 break;
215 }
216
217 return true;
218 }
219
220 void *psi_let_exp_exec(struct psi_let_exp *val, struct psi_decl_arg *darg,
221 void *actual_location, size_t actual_size, struct psi_call_frame *frame)
222 {
223 struct psi_call_frame_symbol *frame_sym;
224
225 frame_sym = psi_call_frame_fetch_symbol(frame, val->var);
226
227 switch (val->kind) {
228 case PSI_LET_NULL:
229 /* FIXME: sizeof_decl_arg */
230 if (darg && darg->var->array_size) {
231 frame_sym->temp_val.ptr = ecalloc(1, psi_decl_arg_get_size(darg));
232 } else {
233 memset(&frame_sym->temp_val, 0, sizeof(frame_sym->temp_val));
234 }
235 break;
236
237 case PSI_LET_TMP:
238 {
239 struct psi_let_stmt *let_temp = psi_impl_get_let(frame->impl,
240 val->data.var);
241 struct psi_call_frame_symbol *temp_arg;
242
243 temp_arg = psi_call_frame_fetch_symbol(frame, let_temp->exp->var);
244 frame_sym->temp_val = *deref_impl_val(temp_arg->ptr, val->data.var);
245 }
246 break;
247
248 case PSI_LET_CALLOC:
249 {
250 zend_long n = psi_long_num_exp(val->data.alloc->nmemb, frame);
251 zend_long s = psi_long_num_exp(val->data.alloc->size, frame);
252 void *tmp = *psi_call_frame_push_auto(frame,
253 safe_emalloc(n, s, sizeof(void *)));
254
255 memset(tmp, 0, n * s + sizeof(void *));
256 frame_sym->temp_val.ptr = tmp;
257 }
258 break;
259
260 case PSI_LET_NUMEXP:
261 frame_sym->temp_val.zend.lval = psi_long_num_exp(val->data.num, frame);
262 break;
263
264 case PSI_LET_CALLBACK:
265 frame_sym->temp_val.ptr = val->data.callback->decl->sym;
266 break;
267
268 case PSI_LET_FUNC:
269 if (!psi_let_func_exec(val, val->data.func, darg, frame)) {
270 return NULL;
271 }
272 break;
273 }
274
275 if (val->is_reference) {
276 frame_sym->ptr = &frame_sym->ival_ptr;
277 } else {
278 frame_sym->ptr = frame_sym->ival_ptr;
279 }
280
281 if (actual_location) {
282 assert(!val->is_reference || actual_size == SIZEOF_VOID_P);
283 memcpy(actual_location, frame_sym->ptr, actual_size);
284 frame_sym->ptr = actual_location;
285 }
286
287 return frame_sym->ptr;
288 }
289
290 struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp)
291 {
292 if (exp) {
293 switch (exp->kind) {
294 case PSI_LET_CALLBACK:
295 return exp->data.callback->func;
296 case PSI_LET_FUNC:
297 return exp->data.func;
298 default:
299 break;
300 }
301 }
302 return NULL;
303 }
304
305 struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val)
306 {
307 if (!val->var) {
308 const char *name = psi_let_exp_get_decl_var_name(val);
309
310 if (name) {
311 val->var = psi_decl_var_init(name, 0, 0);
312 }
313 }
314 return val->var;
315 }
316
317 struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val)
318 {
319 struct psi_let_func* fn = psi_let_exp_get_func(val);
320 return fn ? fn->var : NULL;
321 }
322
323 const char* psi_let_exp_get_decl_var_name(struct psi_let_exp* val)
324 {
325 struct psi_impl_var* var;
326 if (val->var) {
327 return val->var->name;
328 }
329 var = psi_let_exp_get_impl_var(val);
330 if (var) {
331 return &var->name[1];
332 }
333 return NULL;
334 }