num_exp: bitwise ops and op precedence
[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->decl, val, NULL)) {
166 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
167 PSI_WARNING, "Unknown variable '%s'", dvar->name);
168 return false;
169 }
170 break;
171
172 default:
173 if (!psi_decl_var_validate(data, dvar, impl->decl, val, NULL)) {
174 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
175 PSI_WARNING, "Unknown variable '%s'", dvar->name);
176 return false;
177 }
178 break;
179 }
180
181 switch (val->kind) {
182 case PSI_LET_NULL:
183 break;
184 case PSI_LET_TMP:
185 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
186 /* e.g. let foo = *bar; */
187 val->var->pointer_level = val->data.var->pointer_level;
188 val->var->arg = val->data.var->arg;
189 break;
190 case PSI_LET_NUMEXP:
191 if (!psi_num_exp_validate(data, val->data.num, impl, NULL, val, NULL, NULL)) {
192 return false;
193 }
194 break;
195 case PSI_LET_CALLOC:
196 if (!psi_num_exp_validate(data, val->data.alloc->nmemb, impl, NULL, val, NULL, NULL)) {
197 return false;
198 }
199 if (!psi_num_exp_validate(data, val->data.alloc->size, impl, NULL, val, NULL, NULL)) {
200 return false;
201 }
202 break;
203 case PSI_LET_CALLBACK:
204 if (!psi_let_func_validate(data, val, val->data.callback->func, impl)) {
205 return false;
206 }
207 if (!psi_let_callback_validate(data, val, val->data.callback, impl)) {
208 return false;
209 }
210 break;
211 case PSI_LET_FUNC:
212 if (!psi_let_func_validate(data, val, val->data.func, impl)) {
213 return false;
214 }
215 break;
216 }
217
218 return true;
219 }
220
221 void *psi_let_exp_exec(struct psi_let_exp *val, struct psi_decl_arg *darg,
222 void *actual_location, size_t actual_size, struct psi_call_frame *frame)
223 {
224 struct psi_call_frame_symbol *frame_sym;
225
226 frame_sym = psi_call_frame_fetch_symbol(frame, val->var);
227
228 switch (val->kind) {
229 case PSI_LET_NULL:
230 /* FIXME: sizeof_decl_arg */
231 if (darg && darg->var->array_size) {
232 frame_sym->temp_val.ptr = ecalloc(1, psi_decl_arg_get_size(darg));
233 } else {
234 memset(&frame_sym->temp_val, 0, sizeof(frame_sym->temp_val));
235 }
236 break;
237
238 case PSI_LET_TMP:
239 {
240 struct psi_let_stmt *let_temp = psi_impl_get_let(frame->impl,
241 val->data.var);
242 struct psi_call_frame_symbol *temp_arg;
243
244 temp_arg = psi_call_frame_fetch_symbol(frame, let_temp->exp->var);
245 frame_sym->temp_val = *deref_impl_val(temp_arg->ptr, val->data.var);
246 }
247 break;
248
249 case PSI_LET_CALLOC:
250 {
251 zend_long n = psi_long_num_exp(val->data.alloc->nmemb, frame);
252 zend_long s = psi_long_num_exp(val->data.alloc->size, frame);
253 void *tmp = *psi_call_frame_push_auto(frame,
254 safe_emalloc(n, s, sizeof(void *)));
255
256 memset(tmp, 0, n * s + sizeof(void *));
257 frame_sym->temp_val.ptr = tmp;
258 }
259 break;
260
261 case PSI_LET_NUMEXP:
262 {
263 impl_val res;
264 token_t val_type = psi_decl_type_get_real(val->var->arg->type)->type;
265 token_t res_type = psi_num_exp_exec(val->data.num, &res, frame);
266
267 if (val_type == res_type) {
268 frame_sym->temp_val = res;
269 } else {
270 psi_calc_cast(res_type, &res, val_type, &frame_sym->temp_val);
271 }
272 }
273 break;
274
275 case PSI_LET_CALLBACK:
276 frame_sym->temp_val.ptr = val->data.callback->decl->sym;
277 break;
278
279 case PSI_LET_FUNC:
280 if (!psi_let_func_exec(val, val->data.func, darg, frame)) {
281 return NULL;
282 }
283 break;
284 }
285
286 if (val->is_reference) {
287 frame_sym->ptr = &frame_sym->ival_ptr;
288 } else {
289 frame_sym->ptr = frame_sym->ival_ptr;
290 }
291
292 if (actual_location) {
293 assert(!val->is_reference || actual_size == SIZEOF_VOID_P);
294 memcpy(actual_location, frame_sym->ptr, actual_size);
295 frame_sym->ptr = actual_location;
296 }
297
298 return frame_sym->ptr;
299 }
300
301 struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp)
302 {
303 if (exp) {
304 switch (exp->kind) {
305 case PSI_LET_CALLBACK:
306 return exp->data.callback->func;
307 case PSI_LET_FUNC:
308 return exp->data.func;
309 default:
310 break;
311 }
312 }
313 return NULL;
314 }
315
316 struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val)
317 {
318 if (!val->var) {
319 const char *name = psi_let_exp_get_decl_var_name(val);
320
321 if (name) {
322 val->var = psi_decl_var_init(name, 0, 0);
323 }
324 }
325 return val->var;
326 }
327
328 struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val)
329 {
330 struct psi_let_func* fn = psi_let_exp_get_func(val);
331 return fn ? fn->var : NULL;
332 }
333
334 const char* psi_let_exp_get_decl_var_name(struct psi_let_exp* val)
335 {
336 struct psi_impl_var* var;
337 if (val->var) {
338 return val->var->name;
339 }
340 var = psi_let_exp_get_impl_var(val);
341 if (var) {
342 return &var->name[1];
343 }
344 return NULL;
345 }